diff --git a/AndroidManifest.xml b/AndroidManifest.xml index f398b45..febdc23 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -17,40 +17,52 @@ + android:versionCode="20" + android:versionName="2.0.2"> - - - + + + + + - - - + + + + + - + + + + + + + + + + + + + + + + + + + - diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d58144..21ab4f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,94 @@ +- 2.0.2 beta + Major code update: + - Boost performance + + Fixes: + - Fix possible crash turning on/off torch + - Fix camera log + - Fix not all but main security warning in log + - Fix screen off during alert/activity + + Know issues: + - Alternative layout broken + + Next big beta (2.1.0): + - Gesture/Swipe over the cover (bottom&left to: open camera, hang up call, snooze alarm / bottom right to: toggle torch, pickup call, dismiss alarm / bottom top to: pop-up menu) + - Pop-up menu like habeIchVergessen propose (using over cover touch): https://github.com/durka/HallMonitor/issues/18 + - Network connectivity indicator (WIFI/2G/3G/4G): https://github.com/durka/HallMonitor/issues/24 + - Add landscape layout to avoid rotate animation & rotate background app + +- 2.0.1 beta + Major code update: + - Clean/Reorder preferences + - Clean/Reorder strings + - Better preferences change/update + - Better preferences dependencies + + Feature: + - Support 3 modes: + Lock (require admin) + OS PowerManagement + Internal/HallMonitor Powermanagement (require system app) + + Fixes: + - Fix CM 11 LID support + - Fix widget crash (to confirm) + + Know issues: + - Alternative layout broken + + Next big beta (2.1.0): + - Gesture/Swipe over the cover (bottom&left to: open camera, hang up call, snooze alarm / bottom right to: toggle torch, pickup call, dismiss alarm / bottom top to: pop-up menu) + - Pop-up menu like habeIchVergessen propose (using over cover touch): https://github.com/durka/HallMonitor/issues/18 + - Network connectivity indicator (WIFI/2G/3G/4G): https://github.com/durka/HallMonitor/issues/24 + - Add landscape layout to avoid rotate animation & rotate background app + +- 2.0.0 beta + Major code update: + - Rewrite many code to exclude much as possible from UI thread + - Add share value between application parts + + Feature: + - Normally support last CM 11 LID action (to test): turn off Use internal service + - Support 4x1 widget (from my test) + - Add lock mode option when system app (fixed to lock mode if not system app) + - New Input Controls menu under Optional Features + - Pick Up & Hang Up a call without use command line + + Fixes: + - https://github.com/durka/HallMonitor/issues/33 (to test) + - Fix swipe + + Know issues: + - Alternative layout broken + - Must force restart application (through Configuration activity) to get widget content updated after the first attachment + + Next beta (2.1.0): + - Gesture/Swipe over the cover (bottom&left to: open camera, hang up call, snooze alarm / bottom right to: toggle torch, pickup call, dismiss alarm / bottom top to: pop-up menu) + - Pop-up menu like habeIchVergessen propose (using over cover touch): https://github.com/durka/HallMonitor/issues/18 + - Network connectivity indicator (WIFI/2G/3G/4G): https://github.com/durka/HallMonitor/issues/24 + - Add landscape layout to avoid rotate animation & rotate background app + +- 0.5.1 + Features + - Add serrano3gxx support (thank habeIchVergessen) + +- 0.5.0 + Features + - Add Swipe for Torch + - Add Swipe for Alarm + - Add Swipe for Phone (fix) + - Re-add Real Fullscreen (only for software navigation bar) + + Fixes + - Try re-fix (#37) Last used app shows up randomly + - Remove duplicate torch button + - At init unable to turn on directly Torch Control + - Torch icon on CM display correctly (is on/off too when activated outside HallMonitor) + - Clean Alarm code + - Cover mode sensitivity after displaying not before + - Better debug tag + - 0.4.2 Features - Added a new alternative layout @@ -7,8 +98,7 @@ - Stopped TimerTask when receiving a call Partial Fixes - Incoming call screen now works 99% times in both layouts when the screen is off and the cover closed. Does not work if the screen is on and the cover closed (need to open and close the cover manually) - - Alternative and media widgets works for 4x1 widgets and for some 4x2 widget, but -only on alternative layout + - Alternative and media widgets works for 4x1 widgets and for some 4x2 widget, but only on alternative layout - 0.4.1 - Fixes - Touch screen sensitivity now works on S4 Mini Dual Sim diff --git a/README.md b/README.md index 798ea2c..3252f6c 100644 --- a/README.md +++ b/README.md @@ -33,12 +33,25 @@ If you test this on something other than the above (including another carrier's Installation / Usage -------------------- + +STABLE RELEASE The current release is: [0.4.1](https://github.com/durka/HallMonitor/tree/0.4.1) (see [changelog](https://github.com/durka/HallMonitor/blob/0.4.1/CHANGELOG.md)) - The easiest way to install the latest stable version is through [F-Droid](https://f-droid.org/), an "app store" for open source. Here is [Hall Monitor's entry](https://f-droid.org/repository/browse/?fdid=org.durka.hallmonitor). - You can download [`bin/HallMonitor-debug.apk`](https://github.com/durka/HallMonitor/blob/0.4.1/bin/HallMonitor-debug.apk?raw=true) from one of the tagged versions, and install it on your phone assuming you have sideloading turned on. - You can clone the repository at a tagged version and build from source. It's configured as an Eclipse project, but I haven't even used any external libraries yet, so it "should" be "simple" to build with another system such as Android Studio or ant. +CUSTOM RELEASE (manusfreedom) +- You can download [`HallMonitor.apk`](https://github.com/manusfreedom/HallMonitor/tree/master/download/debug) install it on your phone assuming you have sideloading turned on. +But becareful, you can not install it over a system version!!! +- Install in your ROM as system app, use HallMonitor.zip in Recovery mode (https://github.com/manusfreedom/HallMonitor/tree/master/download/CM_SystemApp) +- To update system app, you must copy to time as root the HallMonitor.apk in /system/app + +To switch from one to another you need to completly clean your system (to remove trace of signature): +- Uninstall HallMonitor +- Delete all folders&files named : org.durka.hallmonitor in your /data folder. + + Limitations / Known Issues -------------------------- - Little Things @@ -74,3 +87,16 @@ This should serve as quick guide if you're trying to find your way around my cod - ViewCoverService: the most important file, really, outside of [`Functions.java`](https://github.com/durka/HallMonitor/blob/master/src/org/durka/hallmonitor/Functions.java), is [`ViewCoverService.java`](https://github.com/durka/HallMonitor/blob/master/src/org/durka/hallmonitor/ViewCoverService.java). This is the service that runs all the time and receives events from the proximity sensor, so it can check the hall effect sensor state, and react to view cover events. Happy hacking! File an issue or contact me at [android@alexburka.com](mailto:android@alexburka.com) with any questions. + +Compiling +--------- + +To compile for OS system (install using recovery): +- In AndroidManifest.xml, just after package="org.durka.hallmonitor add (section manifest): +coreApp="true" +android:sharedUserId="android.uid.system" +- In build_signed_system.bat change MODE to release: +SET MODE=release +- In build_signed_system.sh change MODE to release: +MODE=release + diff --git a/cm_certs/build_signed_system.bat b/cm_certs/build_signed_system.bat index 57692c5..dd7f93d 100644 --- a/cm_certs/build_signed_system.bat +++ b/cm_certs/build_signed_system.bat @@ -2,19 +2,13 @@ REM keytool-importkeypair -k cm_platform.keystore -p android -pk8 platform.pk8 - SET JAVA_HOME=c:\Progra~1\Java\jdk1.8 SET PATH=%PATH%;c:\Progra~1\Java\jdk1.8\Bin;C:\Dev\android-sdk-windows\tools;C:\Dev\android-sdk-windows\platform-tools;C:\Dev\apache-ant\bin SET ANDROID_SDK_TOOLS=C:\Dev\android-sdk-windows\build-tools\19.1.0 +SET ANDROID_HOME=C:\\Dev\\android-sdk-windows SET ANDROID_NDK=C:\Dev\android-ndk SET APPNAME=HallMonitor -SET MODE=release +SET MODE=debug ant clean del bin\%APPNAME%-%MODE%-unaligned.apk del bin\%APPNAME%.apk -<<<<<<< HEAD:cm_certs/build_signed_system.txt -%ANDROID_NDK%\ndk-build.cmd clean -%ANDROID_NDK%\ndk-build.cmd -ant %MODE% -IF %MODE%==release java -jar cm_certs\signapk.jar cm_certs\platform.x509.pem cm_certs\platform.pk8 bin\%APPNAME%-%MODE%-unsigned.apk bin\%APPNAME%-%MODE%-unaligned.apk -"%ANDROID_SDK_TOOLS%\zipalign.exe" -v 4 bin\%APPNAME%-%MODE%-unaligned.apk bin\%APPNAME%.apk -======= del libs\armeabi\libGetEvent.so del libs\armeabi-v7a\libGetEvent.so del libs\mips\libGetEvent.so @@ -23,9 +17,10 @@ del libs\x86\libGetEvent.so %ANDROID_NDK%\ndk-build.cmd > build_ndk.log ant %MODE% > build_ant.log IF %MODE%==release java -jar cm_certs\signapk.jar cm_certs\platform.x509.pem cm_certs\platform.pk8 bin\%APPNAME%-%MODE%-unsigned.apk bin\%APPNAME%-%MODE%-unaligned.apk > build_sign.log -"%ANDROID_SDK_TOOLS%\zipalign.exe" -v 4 bin\%APPNAME%-%MODE%-unaligned.apk bin\%APPNAME%.apk > build_align.log -xcopy /y bin\%APPNAME%.apk cm_certs\zip\common -xcopy /s /y libs\* cm_certs\zip\lib -del cm_certs\zip\lib\android-support-v4.jar -echo Please create zip with cm_certs\zip contents ->>>>>>> 59692f4... Updated android-support lib:cm_certs/build_signed_system.bat +IF %MODE%==release "%ANDROID_SDK_TOOLS%\zipalign.exe" -v 4 bin\%APPNAME%-%MODE%-unaligned.apk bin\%APPNAME%.apk > build_align.log +IF %MODE%==release xcopy /y bin\%APPNAME%.apk cm_certs\zip\common +IF %MODE%==release xcopy /s /y libs\* cm_certs\zip\lib +IF %MODE%==release xcopy /s /y bin\%APPNAME%.apk download\CM_SystemApp\HallMonitor.apk +IF %MODE%==release del cm_certs\zip\lib\android-support-v4.jar +IF %MODE%==release echo Please create zip with cm_certs\zip contents +IF %MODE%==debug xcopy /s /y bin\%APPNAME%-debug.apk download\debug\HallMonitor.apk diff --git a/cm_certs/zip/common/HallMonitor.apk b/cm_certs/zip/common/HallMonitor.apk index 201eac5..3c673f8 100644 Binary files a/cm_certs/zip/common/HallMonitor.apk and b/cm_certs/zip/common/HallMonitor.apk differ diff --git a/download/CM_SystemApp/HallMonitor.apk b/download/CM_SystemApp/HallMonitor.apk index f713cca..3c673f8 100644 Binary files a/download/CM_SystemApp/HallMonitor.apk and b/download/CM_SystemApp/HallMonitor.apk differ diff --git a/download/CM_SystemApp/HallMonitor.zip b/download/CM_SystemApp/HallMonitor.zip index d5efb27..69ff615 100644 Binary files a/download/CM_SystemApp/HallMonitor.zip and b/download/CM_SystemApp/HallMonitor.zip differ diff --git a/download/debug/HallMonitor.apk b/download/debug/HallMonitor.apk new file mode 100644 index 0000000..f203d55 Binary files /dev/null and b/download/debug/HallMonitor.apk differ diff --git a/res/drawable/rounded.xml b/res/drawable/rounded.xml index bd2901a..af18687 100644 --- a/res/drawable/rounded.xml +++ b/res/drawable/rounded.xml @@ -10,9 +10,9 @@ + android:bottom="5dp" + android:left="5dp" + android:right="5dp" + android:top="5dp" /> \ No newline at end of file diff --git a/res/layout/activity_alternative.xml b/res/layout/activity_alternative.xml index 8620dcd..0deacfe 100644 --- a/res/layout/activity_alternative.xml +++ b/res/layout/activity_alternative.xml @@ -1,108 +1,99 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - + + + + - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + - + diff --git a/res/layout/activity_default.xml b/res/layout/activity_default.xml index ea99b4e..58c6f4c 100644 --- a/res/layout/activity_default.xml +++ b/res/layout/activity_default.xml @@ -1,108 +1,101 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + + - - - - - - - - - - - - + + + + + + + + - - + + + + - - - - - - - - - + + - + diff --git a/res/layout/preference_switchable_layout.xml b/res/layout/preference_switchable_layout.xml index a165bb9..7d3938b 100644 --- a/res/layout/preference_switchable_layout.xml +++ b/res/layout/preference_switchable_layout.xml @@ -18,7 +18,7 @@ android:layout_gravity="center_vertical" /> - - - - - - - Hall Monitor - Configurazione - Impostazioni - - - Hall Monitor deve essere autorizzato a bloccare lo schermo. - Hall Monitor ha ottenuto i permessi di amministratore! - I permessi di amministratore di Hall Monitor sono stati revocati! - Il servizio view cover richiede i permessi di amministratore - - - Per abilitare questa impostazione seleziona Hall Monitor nella finestra successiva e premi il pulsante indietro. - Per disabilitare questa impostazione deseleziona Hall Monitor nella finestra successiva e premi il pulsante indietro. - Non hai deselezionato la casella, quindi il servizio di notifica è ancora attivo. - Non hai selezionato la casella! Stai cercando di farmi crashare? - - - - Le impostazioni sottostanti sono anche sottomenù! Clicca sul testo per accedere ad altre impostazioni. - - Abilita - Se il servizio view cover è abilitato viene avviato automaticamente all\' avvio del sistema. - Impostazioni Generali - Mostra icone di notifica - Se questa opzione è abilitata, verranno mostrate le icone di notifica quando lo schermo viene acceso con la cover chiusa. - Timeout schermo con cover chiusa - Quando la cover viene chiusa, Hall Monitor rimane attivo per i millisecondi impostati. Se impostato a 0, lo schermo si spegnerà immediatamente. - Abbassa la luminosità della schermata di blocco - Quando la cover è chiusa e Hall Monitor è attivo (vedi sotto), la luminosità dello schermo si deve abbassare? - Mantieni lo stato di amministratore del dispositivo - Quando Hall Monitor viene disabilitato, i permessi di amministratore del dispositivo non vengono revocati. Quando questa opzione viene selezionata, Hall Monitor non chiederà nuovamente di diventare amministratore del dispositivo quando viene abilitato. Utile quando si eseguono operazioni automatiche, es. Tasker. - Mostra Data e Ora - Se selezionato mostra oltre all\' ora anche la data. - Abilita/Disabilita Keyguard - Se selezionata questa opzione rimuove il blocco schermo quando la cover viene aperta. Non funziona se si utilizza una schermata di blocco protetta (Password, PIN, ecc.). - Layout - Passa dal layout di default ad un layout alternativo. - Controlli sperimentali per le chiamate in arrivo - !SPERIMENTALE! Passa dai controlli per le chiamate in arrivo di default "drag and drop" al controllo sperimentale con swipe. I controlli potrebbero non funzionare correttamente, usateli a vostro rischio. - - Impostazioni Root - L\' applicazione dovrebbe venire eseguita con i permessi di superutente (richiesto per la maggior parte delle impostazioni) - per risultati migliori è meglio autorizzare permanentemente il root. - Impostazioni Root - Usa Real Hall - Seleziona per utilizzare il sensore real hall al posto del sensore di prossimità. - - Impostazioni Opzionali - Cliccate per abilitare/disabilitare le impostazioni - - Impostazioni Widget - Cliccate per configurare i widgets - Mostra widget alternativo - Utilizza un widget di terze parti al posto della vista classica di Hall Monitor - Media Widget - Utilizza un widget di terze parti nella finestra della cover quando si riproducono file multimediali o vengono inserite le cuffie. - Controlli Sveglia - Mostra i tasti per fermare o postporre la sveglia nella finestra della cover se la sveglia suona quando la cover è chiusa - - Controlli Chiamata - Mostra i pulsanti per accettare o rifiutare una chiamata quando la cover è chiusa (toccate per altre impostazioni) - Controlli Telefono - Abilita Controlli Telefono - Mostra i pulsanti per accettare o rifiutare una chiamata quando la cover è chiusa - Text-To-Speech - Quando si riceve un chiamata, pronuncia il nome del contatto se questo è salvato nella rubrica. Per poter funzionare questa impostazione richiede le cuffie inserite. - Ritardo Text-To-Speech - Ritardo della pronuncia del nome del contatto quando si riceve una chiamata. - Abilita Speaker - rimuovi controllo cuffie - Inserisci un numero e verifica le tue impostazioni. - inserisci un numero - - Controllo Torcia - Mostra un tasto nella finestra della cover per accendere e spegnere la torcia. - Controllo Torcia Alternativa - Questa è un\' alternativa alla torcia inclusa nelle rom CM. Gli utenti che installano HallMonitor su rom non CM possono usare questa opzione per abilitare la torcia. - Controllo Fotocamera - Mostra un tasto nella finestra della cover per attivare la fotocamera. - - Colore dello sfondo - Seleziona il colore dello sfondo nella finestra della cover quando è chiusa - Colore del testo - Seleziona il colore dell\' orologio nella finestra della cover quando è chiusa - - Impostazioni Blocco Schermo - Scorciatoia per le impostazioni dello schermo di blocco Android - - Su Hall Monitor - Hall Monitor versione 0.4.2.\nProdotto da Alex Burka (@durka), @manusfreedom, @B--B, @Wallace0, @habeIchVergessen, rilasciato su Licenza Apache v2.\nTradotto in italiano da Zanin Marco\nFeedback: android@alexburka.com - Impostazioni - Anteprima - Test - - - Vedo che hai aggiornato alla versione %s! Accertati di cliccare ovunque, ci sono tantissime novità. - OK - - - Applicazione torcia CM non installata - impossibile abilitare la torcia, prova il metodo alternativo! - Impossibile abilitare la torcia, il tuo telefono non supporta questa funzione! - Hai già abilitato la torcia di default, non ti serve un altro tasto per accendere la torcia! - Hai già abilitato la torcia alternativa, non ti serve un altro tasto per accendere la torcia! - - - /sys/devices/virtual/sec/sec_key/hall_detect - WindowActivity - Hello world! - FullscreenActivity - Dummy Button - DUMMY\nCONTENT - SNOOZE - DISMISS - Caller Name - +49 30 1234 5678 - Unknown caller - - - diff --git a/res/values/strings.xml b/res/values/strings.xml index 19b3051..58b963c 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1,5 +1,4 @@ - - + + Hall Monitor + Settings + + + Hall Monitor needs to be able to lock the screen. + Hall Monitor admin status granted! + Hall Monitor admin status revoked! + View cover service requires admin status + + + To enable this setting, check the Hall Monitor box and hit the back button. + To disable this setting, uncheck the Hall Monitor box and hit the back button. + You didn\'t uncheck the box, so the notification service is still running. + You didn\'t check the box! Are you trying to make me crash? + + + + The checkboxes below are also submenus! Click on the text to access more settings. + Enable + Whether the view cover service is enabled and runs at boot + Optional Features + Click through to enable/disable features and access input options. + Display Options + Click through to customize HallMonitor display. + Widget Settings + Click through to configure widgets + Screen Lock Settings + Shortcut to Android screen lock settings + Force restart Hall Monitor + Exit application and restart it after 1 second. + About Hall Monitor + Hall Monitor version 2.0.2.\nProduced by Alex Burka (@durka), @manusfreedom, @B--B, @Wallace0, @habeIchVergessen, released under the Apache v2 License.\nFeedback: android@alexburka.com + + + General Settings + Use OS power management + If on, use OS to manage screen on/off and device sleep. + Use HallMonitor power management + If on, use HallMonitor to manage screen on/off and device sleep during cover event and when cover is closed. Require Hallmonitor in system apps. + Use lock device + If on, lock the device at timeout instead of put device in sleep. Require admin permission. + Keep device admin status + When Hall Monitor is disabled, don\'t relinquish Device Administrator permissions. If checked, Hall Monitor won\'t need to ask to become Device Administrator when you turn it on. May be useful with automation, e.g. Tasker. + Covered screen timeout + When the cover is closed, Hall Monitor stays up for this many milliseconds. If set to 0, the screen turns off immediately (lock the device if lock mode). If OS power management used, only enable system to sleep (it will use screen off timer of OS after this delay). + Use Root access + Should the app run with root permissions, required for internal services and for touch cover feature. Allow permanent root access for best results. + Use internal service + Use internal service Real Hall instead of ROM integrated LID event. Turn off if your ROM support it. + Internal Service + Disable buttons + If checked, the back/menu/home buttons are disabled while the cover is closed. Require Real FullScreen off. + Disable buttons is enable, please disable it to use Real FullScreen + Enable/Dismiss Keyguard + If checked, dismiss the default lock screen when user open the cover. Not working with secure lock screen (Password, PIN, etc.). + Use hardware accelerated display + Use hardware accelerated display. Require a Hall Monitor restart. - - Hall Monitor - Configuration - Settings + + Use Real Hall + Use real hall sensor. + Use Proximity sensor + Use proximity sensor. + + + Layouts + Switch between default layout and an alternative layout. + Use Real FullScreen + Hide all system bar: navigation bar,… Require Disable buttons off. + Real FullScreen is enable, please disable it to use Disable button + Background color + Background of the view you will see through the closed cover + Foreground color + Text color for the clock you will see through the closed cover + Display time and date + If checked, display time and date instead of only time. + + + Show notification icons + If this is enabled, you will see the current notifications icons when the screen turns on while the cover is closed. + + The following feature use touch screen, to be fully working please enable Root access. + Torch Controls + Whether to include a button to turn the torch on and off on the lock screen (touch for more) + Default torch is already enabled, you don\' t need another torch button! + Default CM torch application is not installed - cannot enable torch button, please try alternative method! + Alternative Torch Controls + This is an alternative to stock CM torch App for users that installs HallMonitor in non-CM roms (touch for more) + Alternative torch is already enabled, you don\' t need another torch button! + Cannot enable torch button, your phone does not support this function! + Camera Controls + Whether to include a button to activate the camera on the lock screen + Alarm Controls + Whether to show alarm dismiss and snooze buttons in the cover window if the alarm goes off whilst the cover is closed (touch for more) + Phone Controls + Whether to show phone call accept and reject buttons if the phone rings whilst the cover is closed (touch for more) + Phone Controls + Input Controls + Switch some input event + Input Controls - - Hall Monitor needs to be able to lock the screen. - Hall Monitor admin status granted! - Hall Monitor admin status revoked! - View cover service requires admin status - - - To enable this setting, check the Hall Monitor box and hit the back button. - To disable this setting, uncheck the Hall Monitor box and hit the back button. - You didn\'t uncheck the box, so the notification service is still running. - You didn\'t check the box! Are you trying to make me crash? + + Swipe torch controls + Switch between the default torch push button controls and the experimental functions that uses real swipe control. This function may not work properly, use at your own risk + Swipe camera controls + Switch between the default camera push button controls and the experimental functions that uses real swipe control. This function may not work properly, use at your own risk + Swipe alarm controls + Switch between the default alarm push button controls and the experimental functions that uses real swipe control. This function may not work properly, use at your own risk + Swipe incoming call controls + Switch between the default incoming call drag and drop controls and the experimental functions that uses real swipe control. This function may not work properly, use at your own risk - - - The checkboxes below are also submenus! Click on the text to access more settings. - - Enable - Whether the view cover service is enabled and runs at boot - General Settings - Show notification icons - If this is enabled, you will see the current notifications icons when the screen turns on while the cover is closed. - Covered lock screen timeout - When the cover is closed, Hall Monitor stays up for this many milliseconds. If set to 0, the screen turns off immediately. - Dim covered lock screen - When the cover is closed and Hall Monitor is up (see above), should the screen dim? - Keep device admin status - When Hall Monitor is disabled, don\'t relinquish Device Administrator permissions. If checked, Hall Monitor won\'t need to ask to become Device Administrator when you turn it on. May be useful with automation, e.g. Tasker. - Display time and date - If checked, display time and date instead of only time. - Disable buttons - If checked, the back/menu/home buttons are disabled while the cover is closed. - Enable/Dismiss Keyguard - If checked, dismiss the default lock screen when user open the cover. Not working with secure lock screen (Password, PIN, etc.). - Layouts - Switch between default layout and an alternative layout. - Experimental incoming call controls - !EXPERIMENTAL! Switch between the default incoming call drag and drop controls and the experimental functions that uses real swipe control. This function may not work properly, use at your own risk - - Root Features - Should the app run with root permissions (required for most features) - allow permanent root access for best results. - Root settings - Use Real Hall - Use real hall sensor or use proximity sensor. - - Optional Features - Click through to enable/disable features - - Widget Settings - Click through to configure widgets - Show alternative widget - Whether to use a 3rd party widget inside the cover window as the default view - Media Widget - Whether to use a 3rd party widget inside the cover window to show when media is playing or headphones are connected - Alarm Controls - Whether to show alarm dismiss and snooze buttons in the cover window if the alarm goes off whilst the cover is closed - - Phone Controls - Whether to show phone call accept and reject buttons if the phone rings whilst the cover is closed (touch for more) - Phone Controls - Phone Controls Enable - Whether to show phone call accept and reject buttons if the phone rings whilst the cover is closed - Text-To-Speech - Speaks the caller ID of incoming calls based on your phone´s stored contacts. connected headset is required. - Text-To-Speech Delay - Delay before speaking the caller ID of incoming calls. - Speaker Enable - suppress headset check - Enter a number and verify your setup. - enter a number - - Torch Controls - Whether to include a button to turn the torch on and off on the lock screen - Alternative Torch Controls - This is an alternative to stock CM torch App for users that installs HallMonitor in non-CM roms. - Camera Controls - Whether to include a button to activate the camera on the lock screen - - Background color - Background of the view you will see through the closed cover - Foreground color - Text color for the clock you will see through the closed cover - - Screen Lock Settings - Shortcut to Android screen lock settings - - About Hall Monitor - Hall Monitor version 0.4.2.\nProduced by Alex Burka (@durka), @manusfreedom, @B--B, @Wallace0, @habeIchVergessen, released under the Apache v2 License.\nFeedback: android@alexburka.com - Settings - Preview - Test - - - I see you\'ve upgraded to version %s! Be sure to click on everything, there are tons of new features. - OK - - - Default CM torch application is not installed - cannot enable torch button, please try alternative method! - Cannot enable torch button, your phone does not support this function! - Default torch is already enabled, you don\' t need another torch button! - Alternative torch is already enabled, you don\' t need another torch button! - - - /sys/devices/virtual/sec/sec_key/hall_detect - WindowActivity - Hello world! - FullscreenActivity - Dummy Button - DUMMY\nCONTENT - SNOOZE - DISMISS - Caller Name - +49 30 1234 5678 - Unknown caller + + Settings + Text-To-Speech + Speaks the caller ID of incoming calls based on your phone´s stored contacts. connected headset is required. + Text-To-Speech Delay + Delay before speaking the caller ID of incoming calls. + Speaker Enable + suppress headset check - + + Show alternative widget + Whether to use a 3rd party widget inside the cover window as the default view + Media Widget + Whether to use a 3rd party widget inside the cover window to show when media is playing or headphones are connected + + I see you\'ve upgraded to version %s! Be sure to click on everything, there are tons of new features. + OK + + + /sys/devices/virtual/sec/sec_key/hall_detect + Unknown caller + + + 999 + 11:36 PM Aug 22, 2014 + + + WindowActivity + Hello world! + FullscreenActivity + Dummy Button + DUMMY\nCONTENT + SNOOZE + DISMISS + Caller Name + +49 30 1234 5678 + diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml index e86d80d..7aebaaa 100644 --- a/res/xml/preferences.xml +++ b/res/xml/preferences.xml @@ -39,57 +39,61 @@ android:value="@string/pref_enabled_title" /> - - - - - + + + + + + + android:value="preferences_display" /> - + android:value="@string/pref_displayoptions" /> - - + android:value="preferences_widgets" /> - - - + android:value="@string/pref_widgets" /> + + + + + + + + + + + + diff --git a/res/xml/preferences_features.xml b/res/xml/preferences_features.xml index fba188e..230f3d2 100644 --- a/res/xml/preferences_features.xml +++ b/res/xml/preferences_features.xml @@ -8,35 +8,66 @@ android:summary="@string/pref_notifications_summary" android:defaultValue="false" /> + + + android:defaultValue="false"> + + android:defaultValue="false"> + + android:defaultValue="false"> + + android:defaultValue="false"> + + + + + + + + + + \ No newline at end of file diff --git a/res/xml/preferences_general.xml b/res/xml/preferences_general.xml index b2d3b89..c4a1b2d 100644 --- a/res/xml/preferences_general.xml +++ b/res/xml/preferences_general.xml @@ -1,68 +1,58 @@ - - - + + + + + + + - - - - - - - - - - - - - - - + + + + - - + + + diff --git a/res/xml/preferences_input.xml b/res/xml/preferences_input.xml new file mode 100644 index 0000000..2ab2b8a --- /dev/null +++ b/res/xml/preferences_input.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/res/xml/preferences_root.xml b/res/xml/preferences_internalservice.xml similarity index 54% rename from res/xml/preferences_root.xml rename to res/xml/preferences_internalservice.xml index 5ca3737..d5aa866 100644 --- a/res/xml/preferences_root.xml +++ b/res/xml/preferences_internalservice.xml @@ -6,6 +6,11 @@ android:key="pref_realhall" android:title="@string/pref_realhall" android:summary="@string/pref_realhall_summary" - android:defaultValue="false"/> + android:defaultValue="false" /> + \ No newline at end of file diff --git a/res/xml/preferences_phone.xml b/res/xml/preferences_phone.xml index c38a8bf..d53b55f 100644 --- a/res/xml/preferences_phone.xml +++ b/res/xml/preferences_phone.xml @@ -24,23 +24,4 @@ android:defaultValue="false" /> - - \ No newline at end of file diff --git a/src/afzkl/development/colorpickerview/preference/ColorPickerPreference.java b/src/afzkl/development/colorpickerview/preference/ColorPickerPreference.java index 4742183..dae8f09 100644 --- a/src/afzkl/development/colorpickerview/preference/ColorPickerPreference.java +++ b/src/afzkl/development/colorpickerview/preference/ColorPickerPreference.java @@ -239,7 +239,8 @@ public void writeToParcel(Parcel dest, int flags) { } // Standard creator object using an instance of this class - public static final Parcelable.Creator CREATOR = + @SuppressWarnings("unused") + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { public SavedState createFromParcel(Parcel in) { diff --git a/src/afzkl/development/colorpickerview/view/ColorPickerView.java b/src/afzkl/development/colorpickerview/view/ColorPickerView.java index e743f50..f753eaf 100644 --- a/src/afzkl/development/colorpickerview/view/ColorPickerView.java +++ b/src/afzkl/development/colorpickerview/view/ColorPickerView.java @@ -648,6 +648,11 @@ else if(alpha > 0xff){ return super.onTrackballEvent(event); } + @Override + public boolean performClick() { + return super.performClick(); + } + @Override public boolean onTouchEvent(MotionEvent event) { boolean update = false; @@ -664,7 +669,10 @@ public boolean onTouchEvent(MotionEvent event) { break; case MotionEvent.ACTION_UP: mStartTouchPoint = null; - update = moveTrackersIfNeeded(event); + update = moveTrackersIfNeeded(event); + if(mStartTouchPoint != null){ + performClick(); + } break; } @@ -820,6 +828,7 @@ else if(heightNeeded <= heightAllowed) { setMeasuredDimension(finalWidth, finalHeight); } + @SuppressWarnings("unused") private String modeToString(int mode) { switch(mode) { case MeasureSpec.AT_MOST: @@ -833,6 +842,7 @@ private String modeToString(int mode) { return "ERROR"; } + @SuppressWarnings("unused") private int getPreferredWidth(){ //Our preferred width and height is 200dp for the square sat / val rectangle. int width = (int)(200 * mDensity); @@ -840,6 +850,7 @@ private int getPreferredWidth(){ return (int) (width + HUE_PANEL_WIDTH + PANEL_SPACING); } + @SuppressWarnings("unused") private int getPreferredHeight(){ int height = (int)(200 * mDensity); diff --git a/src/com/manusfreedom/android/Events.java b/src/com/manusfreedom/android/Events.java index 972f96d..0fd7d15 100644 --- a/src/com/manusfreedom/android/Events.java +++ b/src/com/manusfreedom/android/Events.java @@ -21,25 +21,27 @@ package com.manusfreedom.android; import java.util.ArrayList; + import android.util.Log; import eu.chainfire.libsuperuser.Shell; +public class Events { -public class Events -{ - private final static String LT = "Events"; - + public class InputDevice { - + private int m_nVersion; - private String m_szPath, m_szName, m_szLocation, m_szIdStr; + private final String m_szPath; + private String m_szName; + private String m_szLocation; + private String m_szIdStr; private boolean m_bOpen; - + InputDevice(String path) { - m_szPath = path; + m_szPath = path; } - + public int getPollingEvent() { return PollDevice(m_szPath); } @@ -47,149 +49,179 @@ public int getPollingEvent() { public int getAllDevicesPollingEvent() { return PollAllDevices(); } + public int getSuccessfulPollingType() { return getType(m_szPath); } + public int getSuccessfulPollingCode() { return getCode(m_szPath); } + public int getSuccessfulPollingValue() { return getValue(m_szPath); } - + public boolean getOpen() { return m_bOpen; } + public int getVersion() { return m_nVersion; } + public String getPath() { return m_szPath; } + public String getName() { return m_szName; } + public String getLocation() { return m_szLocation; } + public String getIdStr() { return m_szIdStr; } - + public void Close() { - m_bOpen = false; + m_bOpen = false; CloseDevice(m_szPath); } - + /** * function Open : opens an input event node - * @param forceOpen will try to set permissions and then reopen if first open attempt fails + * + * @param forceOpen + * will try to set permissions and then reopen if first open + * attempt fails * @return true if input event node has been opened */ - public boolean Open(boolean forceOpen) { + public boolean Open(boolean forceOpen, boolean rootAccess) { int res = OpenDevice(m_szPath); - // if opening fails, we might not have the correct permissions, try changing 660 to 666 - if (res != 0) { - // possible only if we have root - if(forceOpen && Shell.SU.available()) { - // set new permissions - Shell.SU.run("chmod 666 "+ m_szPath); - // reopen - res = OpenDevice(m_szPath); - } - } - m_nVersion = getDeviceVersion(m_szPath); - m_szName = getDeviceName(m_szPath); - m_szLocation = getDeviceLocation(m_szPath); - m_szIdStr = getDeviceIdStr(m_szPath); - m_bOpen = (res == 0); - // debug - Log.d(LT, "Open:" + m_szPath + " Name:" + m_szName + " Version:" + m_nVersion+" Location:" + m_szLocation + " IdStr:" + m_szIdStr + " Result:" + m_bOpen); - // done, return - return m_bOpen; - } + // if opening fails, we might not have the correct permissions, try + // changing 660 to 666 + if (res != 0) { + // possible only if we have root + if (forceOpen && rootAccess) { + // set new permissions + Shell.SU.run("chmod 666 " + m_szPath); + // reopen + res = OpenDevice(m_szPath); + } + } + m_nVersion = getDeviceVersion(m_szPath); + m_szName = getDeviceName(m_szPath); + m_szLocation = getDeviceLocation(m_szPath); + m_szIdStr = getDeviceIdStr(m_szPath); + m_bOpen = (res == 0); + // debug + Log.d(LT, "Open:" + m_szPath + " Name:" + m_szName + " Version:" + + m_nVersion + " Location:" + m_szLocation + " IdStr:" + + m_szIdStr + " Result:" + m_bOpen); + // done, return + return m_bOpen; + } } - + // top level structures - public ArrayList m_Devs = new ArrayList(); + public ArrayList m_Devs = new ArrayList(); public int Refresh() { - Log.d(LT, "Refreshing"); + Log.d(LT, "Refreshing"); m_Devs.clear(); int n = getDevicesCount(); String devicePath = ""; - for (int i=0; i < n; i++) { + for (int i = 0; i < n; i++) { devicePath = getDeviceAtPosition(i); - Log.d(LT, "Add position:" + i + " Path:" + devicePath); + Log.d(LT, "Add position:" + i + " Path:" + devicePath); m_Devs.add(new InputDevice(getDevicePath(getDeviceAtPosition(i)))); } - return n; + return n; } - + public int AddAllDevices() { Release(); int n = ScanDir(); // return number of devs - if(n > 0) - { + if (n > 0) { return Refresh(); - } - else + } else { return -1; + } } public int AddDevice(String fullpath) { int n = AddOneDevice(fullpath); // return number of devs - if(n > 0) - { - m_Devs.add(new InputDevice(getDevicePath(getDeviceAtPosition(n-1)))); + if (n > 0) { + m_Devs.add(new InputDevice( + getDevicePath(getDeviceAtPosition(n - 1)))); return Refresh(); - } - else + } else { return -1; + } } - + public int Release() { - for (InputDevice idev: m_Devs) + for (InputDevice idev : m_Devs) { idev.Close(); - return Refresh(); + } + return Refresh(); } - + private native static int getDevicesCount(); // return number of devs - private native static int AddOneDevice(String fullpath); // return number of devs + + private native static int AddOneDevice(String fullpath); // return number of + // devs + private native static int ScanDir(); // return number of devs + private native static String getDeviceAtPosition(int index); // + private native static int getDeviceVersion(String fullpath); + private native static String getDevicePath(String fullpath); + private native static String getDeviceName(String fullpath); + private native static String getDeviceLocation(String fullpath); + private native static String getDeviceIdStr(String fullpath); + private native static int OpenDevice(String fullpath); + private native static int CloseDevice(String fullpath); + private native static int PollDevice(String fullpath); + private native static int PollAllDevices(); + private native static int getType(String fullpath); + private native static int getCode(String fullpath); + private native static int getValue(String fullpath); + private native static int getPrintFlags(); - private native static int setPrintFlags(); + private native static int setPrintFlags(); - static { - //Shell.SU.available(); - try { - System.loadLibrary("GetEvent"); - } catch (UnsatisfiedLinkError eGeneric) { - try { - System.load("/data/data/org.durka.hallmonitor/lib/libGetEvent.so"); - } catch (UnsatisfiedLinkError eApkLib) { - try { - System.load("/data/app-lib/HallMonitor/libGetEvent.so"); - } catch (UnsatisfiedLinkError eAppLib) { - System.load("/system/lib/libGetEvent.so"); - } - } - } - } + static { + // Shell.SU.available(); + try { + System.loadLibrary("GetEvent"); + } catch (UnsatisfiedLinkError eGeneric) { + try { + System.load("/data/data/org.durka.hallmonitor/lib/libGetEvent.so"); + } catch (UnsatisfiedLinkError eApkLib) { + try { + System.load("/data/app-lib/HallMonitor/libGetEvent.so"); + } catch (UnsatisfiedLinkError eAppLib) { + System.load("/system/lib/libGetEvent.so"); + } + } + } + } } - diff --git a/src/eu/chainfire/libsuperuser/Shell.java b/src/eu/chainfire/libsuperuser/Shell.java index 43459a4..e91a58c 100644 --- a/src/eu/chainfire/libsuperuser/Shell.java +++ b/src/eu/chainfire/libsuperuser/Shell.java @@ -36,6 +36,7 @@ import android.os.Looper; import eu.chainfire.libsuperuser.StreamGobbler.OnLineListener; +import eu.chainfire.libsuperuser.ShellOnMainThreadException; /** * Class providing functionality to execute commands in a (root) shell diff --git a/src/io/github/homelocker/lib/HomeKeyLocker.java b/src/io/github/homelocker/lib/HomeKeyLocker.java index b1e52ea..a3024b1 100644 --- a/src/io/github/homelocker/lib/HomeKeyLocker.java +++ b/src/io/github/homelocker/lib/HomeKeyLocker.java @@ -1,5 +1,9 @@ package io.github.homelocker.lib; +import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; +import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; +import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; + import org.durka.hallmonitor.R; import android.app.Activity; @@ -10,55 +14,54 @@ import android.view.WindowManager; import android.widget.FrameLayout; -import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; -import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; -import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; - /** * Created by shaobin on 2014/3/22. */ public class HomeKeyLocker { - private OverlayDialog mOverlayDialog; + private OverlayDialog mOverlayDialog; - public void lock(Activity activity) { - if (mOverlayDialog == null) { - mOverlayDialog = new OverlayDialog(activity); - mOverlayDialog.show(); - } - } + public void lock(Activity activity) { + if (mOverlayDialog == null) { + mOverlayDialog = new OverlayDialog(activity); + mOverlayDialog.show(); + } + } - public void unlock() { - if (mOverlayDialog != null) { - mOverlayDialog.dismiss(); - mOverlayDialog = null; - } - } + public void unlock() { + if (mOverlayDialog != null) { + mOverlayDialog.dismiss(); + mOverlayDialog = null; + } + } - private static class OverlayDialog extends AlertDialog { + private static class OverlayDialog extends AlertDialog { - public OverlayDialog(Activity activity) { - super(activity, R.style.OverlayDialog); - WindowManager.LayoutParams params = getWindow().getAttributes(); - params.type = TYPE_SYSTEM_ALERT; - params.dimAmount = 0.0F; // transparent - params.width = 0; - params.height = 0; - params.gravity = Gravity.BOTTOM; - getWindow().setAttributes(params); - getWindow().setFlags(FLAG_SHOW_WHEN_LOCKED | FLAG_NOT_TOUCH_MODAL, 0xffffff); - setOwnerActivity(activity); - setCancelable(false); - } + public OverlayDialog(Activity activity) { + super(activity, R.style.OverlayDialog); + WindowManager.LayoutParams params = getWindow().getAttributes(); + params.type = TYPE_SYSTEM_ALERT; + params.dimAmount = 0.0F; // transparent + params.width = 0; + params.height = 0; + params.gravity = Gravity.BOTTOM; + getWindow().setAttributes(params); + getWindow().setFlags(FLAG_SHOW_WHEN_LOCKED | FLAG_NOT_TOUCH_MODAL, + 0xffffff); + setOwnerActivity(activity); + setCancelable(false); + } - public final boolean dispatchTouchEvent(MotionEvent motionevent) { - return true; - } + @Override + public final boolean dispatchTouchEvent(MotionEvent motionevent) { + return true; + } - protected final void onCreate(Bundle bundle) { - super.onCreate(bundle); - FrameLayout framelayout = new FrameLayout(getContext()); - framelayout.setBackgroundColor(0); - setContentView(framelayout); - } - } + @Override + protected final void onCreate(Bundle bundle) { + super.onCreate(bundle); + FrameLayout framelayout = new FrameLayout(getContext()); + framelayout.setBackgroundColor(0); + setContentView(framelayout); + } + } } diff --git a/src/org/durka/hallmonitor/AdminReceiver.java b/src/org/durka/hallmonitor/AdminReceiver.java index ef7633b..dfa96ca 100644 --- a/src/org/durka/hallmonitor/AdminReceiver.java +++ b/src/org/durka/hallmonitor/AdminReceiver.java @@ -17,18 +17,27 @@ import android.app.admin.DeviceAdminReceiver; import android.content.Context; import android.content.Intent; - +import android.util.Log; +import android.widget.Toast; public class AdminReceiver extends DeviceAdminReceiver { - + private final String LOG_TAG = "Hall.AR"; + @Override public void onEnabled(Context context, Intent intent) { - Functions.Events.device_admin_status(context, true); + Log.d(LOG_TAG + ".status", + "Device admin status called with admin status: " + true); + + Toast.makeText(context, context.getString(R.string.admin_granted), + Toast.LENGTH_SHORT).show(); } - + @Override public void onDisabled(Context context, Intent intent) { - Functions.Events.device_admin_status(context, false); - } + Log.d(LOG_TAG + ".status", + "Device admin status called with admin status: " + false); + Toast.makeText(context, context.getString(R.string.admin_revoked), + Toast.LENGTH_SHORT).show(); + } } diff --git a/src/org/durka/hallmonitor/BootReceiver.java b/src/org/durka/hallmonitor/BootReceiver.java deleted file mode 100644 index bcfad81..0000000 --- a/src/org/durka/hallmonitor/BootReceiver.java +++ /dev/null @@ -1,26 +0,0 @@ -/* Copyright 2013 Alex Burka - - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.durka.hallmonitor; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; - -public class BootReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - Functions.Events.boot(context); - } -} diff --git a/src/org/durka/hallmonitor/CallDragListener.java b/src/org/durka/hallmonitor/CallDragListener.java index d491a59..881c342 100644 --- a/src/org/durka/hallmonitor/CallDragListener.java +++ b/src/org/durka/hallmonitor/CallDragListener.java @@ -1,50 +1,62 @@ package org.durka.hallmonitor; +import android.content.Intent; import android.util.Log; import android.view.DragEvent; import android.view.View; public class CallDragListener implements View.OnDragListener { - - public boolean onDrag(View v, DragEvent dragevent) { - View dragView = (View) dragevent.getLocalState(); - - switch (dragevent.getAction()) { - case DragEvent.ACTION_DRAG_STARTED: - Log.d("DragnDrop", "Event received"); - break; - case DragEvent.ACTION_DRAG_ENTERED: - Log.d("DragnDrop", "Icon now is in target area"); - break; - case DragEvent.ACTION_DRAG_EXITED: - Log.d("DragnDrop", "Icon now is out of the target area"); - break; - case DragEvent.ACTION_DROP: { - if (dragevent.getClipDescription().getLabel().equals("Pickup")) { - Functions.Actions.pickup_call(); - dragView.setVisibility(View.VISIBLE); - Log.d("DragnDrop", "PickUp Call"); - } if (dragevent.getClipDescription().getLabel().equals("Hang")) { - Functions.Actions.hangup_call(); - dragView.setVisibility(View.VISIBLE); - Log.d("DragnDrop", "Hangup Call"); - } - } - Log.d("DragnDrop", "Icon dropped in target area"); - break; - case DragEvent.ACTION_DRAG_ENDED: - if (dropEventNotHandled(dragevent)) { - dragView.setVisibility(View.VISIBLE); - Log.d("DragnDrop", "Not dropped in target area, restoring default"); - } - break; - } - return true; - } + @Override + public boolean onDrag(View v, DragEvent dragevent) { - private boolean dropEventNotHandled(DragEvent event) { - return !event.getResult(); - } + View dragView = (View) dragevent.getLocalState(); + + switch (dragevent.getAction()) { + case DragEvent.ACTION_DRAG_STARTED: + Log.d("DragnDrop", "Event received"); + break; + case DragEvent.ACTION_DRAG_ENTERED: + Log.d("DragnDrop", "Icon now is in target area"); + break; + case DragEvent.ACTION_DRAG_EXITED: + Log.d("DragnDrop", "Icon now is out of the target area"); + break; + case DragEvent.ACTION_DROP: { + if (dragevent.getClipDescription().getLabel().equals("Pickup")) { + Intent pickUpCallIntent = new Intent(v.getContext(), + CoreService.class); + pickUpCallIntent.putExtra(CoreApp.CS_EXTRA_TASK, + CoreApp.CS_TASK_PICKUP_CALL); + v.getContext().startService(pickUpCallIntent); + dragView.setVisibility(View.VISIBLE); + Log.d("DragnDrop", "PickUp Call"); + } + if (dragevent.getClipDescription().getLabel().equals("Hang")) { + Intent hangUpCallIntent = new Intent(v.getContext(), + CoreService.class); + hangUpCallIntent.putExtra(CoreApp.CS_EXTRA_TASK, + CoreApp.CS_TASK_HANGUP_CALL); + v.getContext().startService(hangUpCallIntent); + dragView.setVisibility(View.VISIBLE); + Log.d("DragnDrop", "Hangup Call"); + } + } + Log.d("DragnDrop", "Icon dropped in target area"); + break; + case DragEvent.ACTION_DRAG_ENDED: + if (dropEventNotHandled(dragevent)) { + dragView.setVisibility(View.VISIBLE); + Log.d("DragnDrop", + "Not dropped in target area, restoring default"); + } + break; + } + return true; + } + + private boolean dropEventNotHandled(DragEvent event) { + return !event.getResult(); + } } diff --git a/src/org/durka/hallmonitor/CameraPreview.java b/src/org/durka/hallmonitor/CameraPreview.java index 74cb0ff..d9b12d9 100644 --- a/src/org/durka/hallmonitor/CameraPreview.java +++ b/src/org/durka/hallmonitor/CameraPreview.java @@ -5,6 +5,7 @@ import java.text.SimpleDateFormat; import java.util.Date; +import android.annotation.SuppressLint; import android.app.Activity; import android.content.ContentValues; import android.content.Context; @@ -23,180 +24,219 @@ import android.view.SurfaceView; /** A basic Camera preview class */ -public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback { - private SurfaceHolder mHolder; - private Camera mCamera = null; - private OrientationEventListener mOrientationListener; - private int mOrientation; - public static final int MEDIA_TYPE_IMAGE = 1; - - public static final String DCIM = - Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).toString(); - - public static final String DIRECTORY = DCIM + "/Camera"; - - final PictureCallback mPicture = new PictureCallback() { - - public void onPictureTaken(byte[] data, Camera camera) { - - Log.d("hm-cam", "saving picture to gallery"); - - // Create a media file name - String title = "IMG_"+ new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); - - String path = DIRECTORY + '/' + title + ".jpg"; - - FileOutputStream out = null; - try { - out = new FileOutputStream(path); - out.write(data); - } catch (Exception e) { - Log.e("hm-cam", "Failed to write data", e); - } finally { - try { - out.close(); - } catch (Exception e) { - Log.e("hm-cam", "Failed to close file after write", e); - } - } - - // Insert into MediaStore. - ContentValues values = new ContentValues(5); - values.put(ImageColumns.TITLE, title); - values.put(ImageColumns.DISPLAY_NAME, title + ".jpg"); - values.put(ImageColumns.DATE_TAKEN, System.currentTimeMillis()); - values.put(ImageColumns.DATA, path); - // Clockwise rotation in degrees. 0, 90, 180, or 270. - Log.d("hm-cam", "saving photo with orientation=" + mOrientation); - values.put(ImageColumns.ORIENTATION, mOrientation); - - Uri uri = null; - try { - uri = Functions.defaultActivity.getContentResolver().insert(Images.Media.EXTERNAL_CONTENT_URI, values); - } catch (Throwable th) { - // This can happen when the external volume is already mounted, but - // MediaScanner has not notify MediaProvider to add that volume. - // The picture is still safe and MediaScanner will find it and - // insert it into MediaProvider. The only problem is that the user - // cannot click the thumbnail to review the picture. - Log.e("cp.pictureTaken", "Failed to write MediaStore" + th); - } - - Functions.Actions.end_camera(Functions.defaultActivity); - } - }; - - public CameraPreview(Context ctx, AttributeSet as) { - super(ctx, as); - - Log.d("hm-cam", "context/attributeset constructor"); - - mHolder = getHolder(); - mHolder.addCallback(this); - - mOrientationListener = new OrientationEventListener(ctx, SensorManager.SENSOR_DELAY_NORMAL) { +public class CameraPreview extends SurfaceView implements + SurfaceHolder.Callback { + private final String LOG_TAG = "Hall.camera"; + + private final SurfaceHolder mHolder; + private Camera mCamera = null; + private final OrientationEventListener mOrientationListener; + private int mOrientation; + private final CoreStateManager mStateManager; + public static final int MEDIA_TYPE_IMAGE = 1; + + public static final String DCIM = Environment + .getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) + .toString(); + + public static final String DIRECTORY = DCIM + "/Camera"; + + final PictureCallback mPicture = new PictureCallback() { + + @Override + @SuppressLint("SimpleDateFormat") + public void onPictureTaken(byte[] data, Camera camera) { + + Log.d(LOG_TAG, "saving picture to gallery"); + + // Create a media file name + String title = "IMG_" + + new SimpleDateFormat("yyyyMMdd_HHmmss") + .format(new Date()); + + String path = DIRECTORY + '/' + title + ".jpg"; + + FileOutputStream out = null; + try { + out = new FileOutputStream(path); + out.write(data); + } catch (Exception e) { + Log.e("hm-cam", "Failed to write data", e); + } finally { + try { + out.close(); + } catch (Exception e) { + Log.e("hm-cam", "Failed to close file after write", e); + } + } + + // Insert into MediaStore. + ContentValues values = new ContentValues(5); + values.put(ImageColumns.TITLE, title); + values.put(ImageColumns.DISPLAY_NAME, title + ".jpg"); + values.put(ImageColumns.DATE_TAKEN, System.currentTimeMillis()); + values.put(ImageColumns.DATA, path); + // Clockwise rotation in degrees. 0, 90, 180, or 270. + Log.d(LOG_TAG, "saving photo with orientation=" + mOrientation); + values.put(ImageColumns.ORIENTATION, mOrientation); + + @SuppressWarnings("unused") + Uri uri = null; + try { + uri = mStateManager.getDefaultActivity().getContentResolver() + .insert(Images.Media.EXTERNAL_CONTENT_URI, values); + } catch (Throwable th) { + // This can happen when the external volume is already mounted, + // but + // MediaScanner has not notify MediaProvider to add that volume. + // The picture is still safe and MediaScanner will find it and + // insert it into MediaProvider. The only problem is that the + // user + // cannot click the thumbnail to review the picture. + Log.e("cp.pictureTaken", "Failed to write MediaStore" + th); + } + + mStateManager.getDefaultActivity().stopCamera(); + mStateManager.getDefaultActivity().startCamera(); + } + }; + + public CameraPreview(Context ctx) { + this(ctx, null, 0); + } + + public CameraPreview(Context ctx, AttributeSet as) { + this(ctx, as, 0); + } + + public CameraPreview(Context ctx, AttributeSet as, int defStyle) { + super(ctx, as, defStyle); + + Log.d(LOG_TAG, "context/attributeset/defstyle constructor"); + + mStateManager = ((CoreApp) ctx.getApplicationContext()) + .getStateManager(); + + mHolder = getHolder(); + mHolder.addCallback(this); + + mOrientationListener = new OrientationEventListener(ctx, + SensorManager.SENSOR_DELAY_NORMAL) { @Override public void onOrientationChanged(int angle) { - mOrientation = ((int)(Math.round(angle/90.0)*90) + 90) % 360; + mOrientation = ((int) (Math.round(angle / 90.0) * 90) + 90) % 360; } - - }; - } - - public void capture() { - Log.d("hm-cam", "capture"); - mCamera.takePicture(null, null, mPicture); - } - - public void surfaceCreated(SurfaceHolder holder) { - // The Surface has been created, now tell the camera where to draw the preview. - Log.d("hm-cam", "surface created!"); - - mOrientationListener.enable(); - - // Create an instance of Camera + + }; + } + + public void capture() { + Log.d(LOG_TAG, "capture"); + mCamera.takePicture(null, null, mPicture); + } + + @Override + public void surfaceCreated(SurfaceHolder holder) { + // The Surface has been created, now tell the camera where to draw the + // preview. + Log.d(LOG_TAG, "surface created!"); + + mOrientationListener.enable(); + + // Create an instance of Camera if (mCamera == null) { mCamera = CameraHelper.getCameraInstance(); - CameraHelper.updateCameraParametersPreference(Functions.defaultActivity, mCamera); - + CameraHelper.updateCameraParametersPreference( + mStateManager.getDefaultActivity(), mCamera); + try { - mCamera.setPreviewDisplay(holder); - mCamera.startPreview(); - } catch (IOException e) { - Log.d("hm-cam", "Error setting camera preview: " + e.getMessage()); - } + mCamera.setPreviewDisplay(holder); + mCamera.startPreview(); + } catch (IOException e) { + Log.e(LOG_TAG, + "Error setting camera preview: " + e.getMessage()); + } + } + } + + @Override + public void surfaceDestroyed(SurfaceHolder holder) { + // empty. Take care of releasing the Camera preview in your activity. + Log.d(LOG_TAG, "surface destroyed!"); + + mOrientationListener.disable(); + + if (mCamera != null) { + mCamera.release(); // release the camera for other applications + mCamera = null; } - } - - public void surfaceDestroyed(SurfaceHolder holder) { - // empty. Take care of releasing the Camera preview in your activity. - Log.d("hm-cam", "surface destroyed!"); - - mOrientationListener.disable(); - - if (mCamera != null){ - mCamera.release(); // release the camera for other applications - mCamera = null; - } - } - - public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { - // If your preview can change or rotate, take care of those events here. - // Make sure to stop the preview before resizing or reformatting it. - - Log.d("hm-cam", "surface changed!"); - - if (mHolder.getSurface() == null || Functions.defaultActivity == null) { - // preview surface does not exist - return; - } - - // stop preview before making changes - try { - mCamera.stopPreview(); - } catch (Exception e){ - // ignore: tried to stop a non-existent preview - } - - // set preview size and make any resize, rotate or - // reformatting changes here - setCameraDisplayOrientation(Functions.defaultActivity, 0, mCamera); - - // start preview with new settings - try { - mCamera.setPreviewDisplay(mHolder); - mCamera.startPreview(); - } catch (Exception e){ - Log.d("hm-cam", "Error restarting camera preview: " + e.getMessage()); - } - } - - - public static void setCameraDisplayOrientation(Activity activity, - int cameraId, android.hardware.Camera camera) { - android.hardware.Camera.CameraInfo info = - new android.hardware.Camera.CameraInfo(); - android.hardware.Camera.getCameraInfo(cameraId, info); - int rotation = activity.getWindowManager().getDefaultDisplay() - .getRotation(); - int degrees = 0; - switch (rotation) { - case Surface.ROTATION_0: degrees = 0; break; - case Surface.ROTATION_90: degrees = 90; break; - case Surface.ROTATION_180: degrees = 180; break; - case Surface.ROTATION_270: degrees = 270; break; - } - - int result; - if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { - result = (info.orientation + degrees) % 360; - result = (360 - result) % 360; // compensate the mirror - } else { // back-facing - result = (info.orientation - degrees + 360) % 360; - } - camera.setDisplayOrientation(result); - } - - + } + + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { + // If your preview can change or rotate, take care of those events here. + // Make sure to stop the preview before resizing or reformatting it. + + Log.d(LOG_TAG, "surface changed!"); + + if (mHolder.getSurface() == null + || mStateManager.getDefaultActivity() == null) { + // preview surface does not exist + return; + } + + // stop preview before making changes + try { + mCamera.stopPreview(); + } catch (Exception e) { + // ignore: tried to stop a non-existent preview + } + + // set preview size and make any resize, rotate or + // reformatting changes here + setCameraDisplayOrientation(mStateManager.getDefaultActivity(), 0, + mCamera); + + // start preview with new settings + try { + mCamera.setPreviewDisplay(mHolder); + mCamera.startPreview(); + } catch (Exception e) { + Log.d(LOG_TAG, "Error restarting camera preview: " + e.getMessage()); + } + } + + public static void setCameraDisplayOrientation(Activity activity, + int cameraId, android.hardware.Camera camera) { + android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo(); + android.hardware.Camera.getCameraInfo(cameraId, info); + int rotation = activity.getWindowManager().getDefaultDisplay() + .getRotation(); + int degrees = 0; + switch (rotation) { + case Surface.ROTATION_0: + degrees = 0; + break; + case Surface.ROTATION_90: + degrees = 90; + break; + case Surface.ROTATION_180: + degrees = 180; + break; + case Surface.ROTATION_270: + degrees = 270; + break; + } + + int result; + if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { + result = (info.orientation + degrees) % 360; + result = (360 - result) % 360; // compensate the mirror + } else { // back-facing + result = (info.orientation - degrees + 360) % 360; + } + camera.setDisplayOrientation(result); + } + } \ No newline at end of file diff --git a/src/org/durka/hallmonitor/Configuration.java b/src/org/durka/hallmonitor/Configuration.java index c22ba02..5ad5905 100644 --- a/src/org/durka/hallmonitor/Configuration.java +++ b/src/org/durka/hallmonitor/Configuration.java @@ -14,102 +14,295 @@ */ package org.durka.hallmonitor; +import java.lang.reflect.Constructor; + +import android.app.Activity; +import android.appwidget.AppWidgetManager; +import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.preference.Preference; import android.preference.PreferenceActivity; import android.preference.PreferenceFragment; -import android.preference.PreferenceManager; import android.util.Log; import android.view.MenuItem; - -import java.lang.reflect.Constructor; +import android.widget.Toast; public class Configuration extends PreferenceActivity { - private final String LOG_TAG = "Configuration"; + private final String LOG_TAG = "Configuration"; + + private CoreStateManager mStateManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - - Functions.configurationActivity = this; + Log.d(LOG_TAG + ".onCreate", "creating"); + + mStateManager = ((CoreApp) getApplicationContext()).getStateManager(); + + // pass a reference back to the state manager + if (!mStateManager.setConfigurationActivity(this)) { + this.finish(); + return; + } + + PreferenceFragment preferenceFragment = new PreferenceFragmentLoader(); + + // add extra resource to load xml + Bundle arguments = new Bundle(1); + arguments.putCharSequence("resource", "preferences"); + preferenceFragment.setArguments(arguments); + + getFragmentManager().beginTransaction() + .replace(android.R.id.content, preferenceFragment).commit(); + } + + @Override + protected void onStart() { + Log.d(LOG_TAG + ".onStart", "starting"); + + super.onStart(); + } + + @Override + protected void onResume() { + super.onResume(); + Log.d(LOG_TAG + ".onResume", "resuming"); + + if (mStateManager.getDefaultActivityRunning()) { + mStateManager.closeDefaultActivity(); + } + + mStateManager.requestAdmin(); + } + + @Override + protected void onPause() { + Log.d(LOG_TAG + ".onPause", "pausing"); + + super.onPause(); + } + + @Override + protected void onStop() { + Log.d(LOG_TAG + ".onStop", "stopping"); - PreferenceFragment preferenceFragment = new PreferenceFragmentLoader(); + super.onStop(); + } - // add extra resource to load xml - Bundle arguments = new Bundle(1); - arguments.putCharSequence("resource", "preferences"); - preferenceFragment.setArguments(arguments); + @Override + protected void onDestroy() { + Log.d(LOG_TAG + ".onDestroy", "detroying"); - getFragmentManager().beginTransaction().replace(android.R.id.content, preferenceFragment).commit(); + mStateManager.setConfigurationActivity(null); + super.onDestroy(); } - + @Override public void onActivityResult(int request, int result, Intent data) { super.onActivityResult(request, result, data); - Functions.Events.activity_result(this, request, result, data); + activity_result(this, request, result, data); + } + + @Override + public boolean onPreferenceStartFragment(PreferenceFragment caller, + Preference preference) { + try { + // create new instance of class + Class c = Class.forName(preference.getFragment()); + Constructor cons = c.getConstructor(); + Object object = cons.newInstance(); + + // add preference fragment + if (object instanceof PreferenceFragment) { + PreferenceFragment preferenceFragment = (PreferenceFragment) object; + preferenceFragment.setArguments(preference.getExtras()); + + getFragmentManager().beginTransaction() + .replace(android.R.id.content, preferenceFragment) + .addToBackStack((String) getActionBar().getTitle()) + .commit(); + getFragmentManager().executePendingTransactions(); + + // update action bar + updateHeaderTitle(preference.getExtras().getString("title")); + } else { + Log_d(LOG_TAG, + "onPreferenceStartFragment: given class is not a PreferenceFragment"); + } + } catch (Exception e) { + Log_d(LOG_TAG, "onPreferenceStartFragment: exception occurred! " + + e.getMessage()); + } + + return true; // the default implementation returns true. documentation + // is silent. FIXME + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + // Respond to the action bar's Up/Home button + case android.R.id.home: + onBackPressed(); + return true; + } + + return super.onOptionsItemSelected(item); } - @Override - public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference preference) { - try { - // create new instance of class - Class c = Class.forName(preference.getFragment()); - Constructor cons = c.getConstructor(); - Object object = cons.newInstance(); - - // add preference fragment - if (object instanceof PreferenceFragment) { - PreferenceFragment preferenceFragment = (PreferenceFragment)object; - preferenceFragment.setArguments(preference.getExtras()); - - getFragmentManager().beginTransaction().replace(android.R.id.content, preferenceFragment).addToBackStack((String) getActionBar().getTitle()).commit(); - getFragmentManager().executePendingTransactions(); - - // update action bar - updateHeaderTitle(preference.getExtras().getString("title")); - } else - Log_d(LOG_TAG, "onPreferenceStartFragment: given class is not a PreferenceFragment"); - } catch (Exception e) { - Log_d(LOG_TAG, "onPreferenceStartFragment: exception occurred! " + e.getMessage()); - } - - return true; // the default implementation returns true. documentation is silent. FIXME - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - // Respond to the action bar's Up/Home button - case android.R.id.home: - onBackPressed(); - return true; - } - - return super.onOptionsItemSelected(item); - } - - @Override - public void onBackPressed() { - CharSequence title = getTitle(); - int idx; - - if ((idx = getFragmentManager().getBackStackEntryCount()) > 0) { - title = getFragmentManager().getBackStackEntryAt(idx - 1).getName(); - getFragmentManager().popBackStackImmediate(); // TODO test back stack - } else - super.onBackPressed(); - - updateHeaderTitle(title); - } - - private void updateHeaderTitle(CharSequence title) { - getActionBar().setTitle(title); - getActionBar().setDisplayHomeAsUpEnabled((getFragmentManager().getBackStackEntryCount() > 0)); - } - - private void Log_d(String tag, String msg) { - if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean("pref_dev_opts_debug", false)) - Log.d(tag, msg); - } + @Override + public void onBackPressed() { + CharSequence title = getTitle(); + int idx; + + if ((idx = getFragmentManager().getBackStackEntryCount()) > 0) { + title = getFragmentManager().getBackStackEntryAt(idx - 1).getName(); + getFragmentManager().popBackStackImmediate(); // TODO test back + // stack + } else { + super.onBackPressed(); + } + + updateHeaderTitle(title); + } + + private void updateHeaderTitle(CharSequence title) { + getActionBar().setTitle(title); + getActionBar().setDisplayHomeAsUpEnabled( + (getFragmentManager().getBackStackEntryCount() > 0)); + } + + /** + * The Configuration activity acts as the main activity for the app. Any + * events received into its onActivityReceived method are passed on to be + * handled here. + * + * @param ctx + * Application context. + * @param request + * Request Activity ID. + * @param result + * Result Activity ID. + * @param data + * Intent that holds the data received. + */ + public void activity_result(Context ctx, int request, int result, + Intent data) { + Log.d(LOG_TAG + ".Evt.activity_result", + "Activity result received: request=" + + Integer.toString(request) + ", result=" + + Integer.toString(result)); + switch (request) { + // call back for admin access request + case CoreApp.DEVICE_ADMIN_WAITING: + if (result == Activity.RESULT_OK) { + mStateManager.refreshAdminApp(); + } else { + mStateManager.refreshAdminApp(); + // we asked to be an admin and the user clicked Cancel + // (why?) + // complain, and un-check pref_enabled + Toast.makeText(ctx, ctx.getString(R.string.admin_refused), + Toast.LENGTH_SHORT).show(); + } + break; + // call back for appwidget pick + case CoreApp.REQUEST_PICK_APPWIDGET: + // widget picked + mStateManager.setWidgetSettingsOngoing(true); + if (result == Activity.RESULT_OK) { + // widget chosen so launch configurator + mStateManager.hmAppWidgetManager + .configureWidget(data + .getStringExtra(CoreApp.EXTRA_APPWIDGET_TYPE), + data); + } else { + // choose dialog cancelled so clean up + int appWidgetId = data.getIntExtra( + AppWidgetManager.EXTRA_APPWIDGET_ID, -1); + if (appWidgetId != -1) { + mStateManager.hmAppWidgetManager + .deleteAppWidgetId(appWidgetId); + mStateManager + .getPreference() + .edit() + .putBoolean( + "pref_" + + data.getStringExtra(CoreApp.EXTRA_APPWIDGET_TYPE) + + "_widget", false) // FIXME + // this is a + // huge hack + .commit(); + } + } + break; + + // call back for appwidget configure + case CoreApp.REQUEST_CONFIGURE_APPWIDGET: + mStateManager.setWidgetSettingsOngoing(false); + // widget configured + if (result == Activity.RESULT_OK) { + // widget configured successfully so create it + mStateManager.hmAppWidgetManager + .createWidget(data + .getStringExtra(CoreApp.EXTRA_APPWIDGET_TYPE), + data); + } else { + // configure dialog cancelled so clean up + if (data != null) { + int appWidgetId = data.getIntExtra( + AppWidgetManager.EXTRA_APPWIDGET_ID, -1); + if (appWidgetId != -1) { + mStateManager.hmAppWidgetManager + .deleteAppWidgetId(appWidgetId); + mStateManager + .getPreference() + .edit() + .putBoolean( + "pref_" + + data.getStringExtra(CoreApp.EXTRA_APPWIDGET_TYPE) + + "_widget", false) // FIXME + // this + // is a + // huge + // hack + .commit(); + } + } + } + break; + + case CoreApp.NOTIFICATION_LISTENER_ON: + Log.d(LOG_TAG + ".Evt.activity_result", + "return from checking the box"); + mStateManager.setNotificationSettingsOngoing(false); + if (!mStateManager.getServiceRunning(NotificationService.class)) { + Toast.makeText(ctx, + ctx.getString(R.string.notif_left_unchecked), + Toast.LENGTH_SHORT).show(); + mStateManager.getPreference().edit() + .putBoolean("pref_do_notifications", false).commit(); + } + break; + case CoreApp.NOTIFICATION_LISTENER_OFF: + Log.d(LOG_TAG + ".Evt.activity_result", + "return from unchecking the box"); + mStateManager.setNotificationSettingsOngoing(false); + if (mStateManager.getServiceRunning(NotificationService.class)) { + Toast.makeText(ctx, ctx.getString(R.string.notif_left_checked), + Toast.LENGTH_SHORT).show(); + mStateManager.getPreference().edit() + .putBoolean("pref_do_notifications", true).commit(); + } + break; + } + } + + private void Log_d(String tag, String msg) { + if (mStateManager.getPreference().getBoolean("pref_dev_opts_debug", + false)) { + Log.d(tag, msg); + } + } } diff --git a/src/org/durka/hallmonitor/CoreApp.java b/src/org/durka/hallmonitor/CoreApp.java new file mode 100644 index 0000000..196e776 --- /dev/null +++ b/src/org/durka/hallmonitor/CoreApp.java @@ -0,0 +1,99 @@ +/* Copyright 2013 Alex Burka + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.durka.hallmonitor; + +import android.app.Application; + +public class CoreApp extends Application { + + // Callback identifiers for startActivityForResult, used by the preference + // screen + public static final int DEVICE_ADMIN_WAITING = 42; + public static final int REQUEST_PICK_APPWIDGET = 9; + public static final int REQUEST_CONFIGURE_APPWIDGET = 5; + public static final int NOTIFICATION_LISTENER_ON = 0xDEAD; + public static final int NOTIFICATION_LISTENER_OFF = 0xBEEF; + + // Supported devices + public static final String DEV_SERRANO_LTE_CM10 = "serranolte"; // GT-I9195 + // CM10.x + public static final String DEV_SERRANO_LTE_CM11 = "serranoltexx"; // GT-I9195 + // CM11.x + public static final String DEV_SERRANO_3G_CM11 = "serrano3gxx"; // GT-I9190 + // CM11.x + public static final String DEV_SERRANO_DS_CM10 = "serranods"; // GT-I9192 + // CM10.x + public static final String DEV_SERRANO_DS_CM11 = "serranodsxx"; // GT-I9192 + // CM11.x + + // CoreService constant + public static final String CS_EXTRA_TASK = "task"; + public static final String CS_EXTRA_STATE = "extra"; + + public static final int CS_TASK_MAINLAUNCH = 1; + public static final int CS_TASK_NOTHING = 2; + public static final int CS_TASK_INCOMMING_CALL = 3; + public static final int CS_TASK_INCOMMING_ALARM = 4; + public static final int CS_TASK_AUTO_BLACKSCREEN = 5; + public static final int CS_TASK_LAUNCH_ACTIVITY = 7; + public static final int CS_TASK_WAKEUP_DEVICE = 8; + public static final int CS_TASK_CHANGE_TOUCHCOVER = 9; + public static final int CS_TASK_TORCH_STATE = 10; + public static final int CS_TASK_TORCH_TOGGLE = 11; + public static final int CS_TASK_CAMERA_TOGGLE = 12; + public static final int CS_TASK_HEADSET_PLUG = 13; + public static final int CS_TASK_SNOOZE_ALARM = 14; + public static final int CS_TASK_DISMISS_ALARM = 15; + public static final int CS_TASK_HANGUP_CALL = 16; + public static final int CS_TASK_PICKUP_CALL = 17; + + public static final String PACKAGE_PHONE_APP = "com.android.dialer"; + public static final String PACKAGE_ALARM_APP = "com.android.deskclock"; + + // DefaultActivity constant + public static final String DA_ACTION_TORCH_STATE_CHANGED = "org.durka.hallmonitor.TORCH_STATE_CHANGED"; + public static final String DA_ACTION_STATE_CHANGED = "org.durka.hallmonitor.DA_STATE_CHANGED"; + public static final String DA_ACTION_WIDGET_REFRESH = "org.durka.hallmonitor.DA_WIDGET_REFRESH"; + public static final String DA_ACTION_NOTIFICATION_REFRESH = "org.durka.hallmonitor.DA_NOTIFICATION_REFRESH"; + public static final String DA_ACTION_BATTERY_REFRESH = "org.durka.hallmonitor.DA_BATTERY_REFRESH"; + public static final String DA_ACTION_START_CAMERA = "org.durka.hallmonitor.DA_START_CAMERA"; + public static final String DA_ACTION_FINISH = "org.durka.hallmonitor.DA_FINISH"; + public static final String DA_ACTION_FREE_SCREEN = "org.durka.hallmonitor.DA_FREE_SCREEN"; + public static final String DA_ACTION_SEND_TO_BACKGROUND = "org.durka.hallmonitor.DA_SEND_TO_BACKGROUND"; + public static final String DA_EXTRA_STATE = "state"; + public static final int DA_EXTRA_STATE_NORMAL = 0; + public static final int DA_EXTRA_STATE_ALARM = 1; + public static final int DA_EXTRA_STATE_PHONE = 2; + public static final int DA_EXTRA_STATE_CAMERA = 3; + + public static final String EXTRA_APPWIDGET_TYPE = "org.durka.hallmonitor.APPWIDGET_TYPE"; + + private static CoreStateManager mStateManager; + + public CoreStateManager getStateManager() { + if (mStateManager == null) { + mStateManager = new CoreStateManager(this); + } + return mStateManager; + } + + public void restart() { + mStateManager.closeDefaultActivity(); + mStateManager.stopServices(); + mStateManager = new CoreStateManager(this); + mStateManager.startServices(); + } +} diff --git a/src/org/durka/hallmonitor/CoreReceiver.java b/src/org/durka/hallmonitor/CoreReceiver.java new file mode 100644 index 0000000..3daffbe --- /dev/null +++ b/src/org/durka/hallmonitor/CoreReceiver.java @@ -0,0 +1,289 @@ +/* Copyright 2013 Alex Burka + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.durka.hallmonitor; + +import android.app.Notification; +import android.app.NotificationManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; +import android.support.v4.content.LocalBroadcastManager; +import android.telephony.TelephonyManager; +import android.util.Log; + +public class CoreReceiver extends BroadcastReceiver { + + private final String LOG_TAG = "Hall.CR"; + + private CoreStateManager mStateManager; + private Context localContext; + + // Action fired when cover state change + public static final String ACTION_LID_STATE_CHANGED = "android.intent.action.LID_STATE_CHANGED"; + public static final String ACTION_INTERNAL_LID_STATE_CHANGED = "org.durka.hallmonitor.LID_STATE_CHANGED"; + public static final String EXTRA_LID_STATE = "state"; + public static final int LID_ABSENT = -1; + public static final int LID_CLOSED = 0; + public static final int LID_OPEN = 1; + // Action fired when alarm goes on + public static final String ALARM_ALERT_ACTION = "com.android.deskclock.ALARM_ALERT"; + // Action to trigger snooze of the alarm + public static final String ALARM_SNOOZE_ACTION = "com.android.deskclock.ALARM_SNOOZE"; + // Action to trigger dismiss of the alarm + public static final String ALARM_DISMISS_ACTION = "com.android.deskclock.ALARM_DISMISS"; + // Action should let us know if the alarm has been killed by another app + public static final String ALARM_DONE_ACTION = "com.android.deskclock.ALARM_DONE"; + // Action to toggle flashlight + public static final String TOGGLE_FLASHLIGHT = "net.cactii.flash2.TOGGLE_FLASHLIGHT"; + // Action when toggle state change + public static final String TORCH_STATE_CHANGED = "net.cactii.flash2.TORCH_STATE_CHANGED"; + // QUICKBOOT_POWERON + public static final String QUICKBOOT_POWERON = "android.intent.action.QUICKBOOT_POWERON"; + // QUICKBOOT_POWERON special HTC + public static final String HTC_QUICKBOOT_POWERON = "com.htc.intent.action.QUICKBOOT_POWERON"; + + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED) + || intent.getAction().equals(QUICKBOOT_POWERON) + || intent.getAction().equals(HTC_QUICKBOOT_POWERON)) { + Log.d(LOG_TAG + ".boot", "Boot called."); + SharedPreferences prefs = PreferenceManager + .getDefaultSharedPreferences(context); + if (prefs.getBoolean("pref_enabled", false)) { + Intent mIntent = new Intent(context, CoreService.class); + context.startService(mIntent); + } + } + + if (CoreStateManager.getInitialized()) { + localContext = CoreStateManager.getContext(); + mStateManager = ((CoreApp) localContext).getStateManager(); + } else { + return; + } + + if (!mStateManager.getPreference().getBoolean("pref_enabled", false)) { + return; + } + + mStateManager.acquireCPUGlobal(); + + if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) { + + Log.d(LOG_TAG + ".screen", "Screen on event received."); + + if (mStateManager.getCoverClosed()) { + Log.d(LOG_TAG + ".screen", + "Cover is closed, display Default Activity."); + mStateManager.setBlackScreenTime(0); + Intent mIntent = new Intent(localContext, CoreService.class); + mIntent.putExtra(CoreApp.CS_EXTRA_TASK, + CoreApp.CS_TASK_LAUNCH_ACTIVITY); + mStateManager.sendToCoreService(mIntent); + } else { + // Log.d(LOG_TAG + ".screen", + // "Cover is open, free everything."); + // mStateManager.freeDevice(); + Log.d(LOG_TAG + ".screen", "Cover is open, send to background."); + Intent stbDAIntent = new Intent( + CoreApp.DA_ACTION_SEND_TO_BACKGROUND); + LocalBroadcastManager.getInstance(localContext) + .sendBroadcastSync(stbDAIntent); + } + + } else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { + Log.d(LOG_TAG + ".screen", "Screen off event received."); + // mStateManager.freeDevice(); + + } else if (intent.getAction().equals(Intent.ACTION_POWER_CONNECTED)) { + Intent batteryDAIntent = new Intent( + CoreApp.DA_ACTION_BATTERY_REFRESH); + LocalBroadcastManager.getInstance(localContext).sendBroadcastSync( + batteryDAIntent); + + Intent mIntent = new Intent(localContext, CoreService.class); + mIntent.putExtra(CoreApp.CS_EXTRA_TASK, + CoreApp.CS_TASK_WAKEUP_DEVICE); + mStateManager.sendToCoreService(mIntent); + + } else if (intent.getAction().equals(Intent.ACTION_POWER_DISCONNECTED)) { + Intent batteryDAIntent = new Intent( + CoreApp.DA_ACTION_BATTERY_REFRESH); + LocalBroadcastManager.getInstance(localContext).sendBroadcastSync( + batteryDAIntent); + + Intent mIntent = new Intent(localContext, CoreService.class); + mIntent.putExtra(CoreApp.CS_EXTRA_TASK, + CoreApp.CS_TASK_WAKEUP_DEVICE); + mStateManager.sendToCoreService(mIntent); + + } else if (intent.getAction().equals(ALARM_ALERT_ACTION)) { + + Log.d(LOG_TAG + ".alarm", "Alarm on event received."); + + // only take action if alarm controls are enabled + if (mStateManager.getPreference().getBoolean("pref_alarm_controls", + false)) { + + Log.d(LOG_TAG + ".alarm", + "Alarm controls are enabled, taking action."); + mStateManager.setAlarmFiring(true); + + Intent mIntent = new Intent(localContext, CoreService.class); + mIntent.putExtra(CoreApp.CS_EXTRA_TASK, + CoreApp.CS_TASK_INCOMMING_ALARM); + mStateManager.sendToCoreService(mIntent); + } else { + Log.d(LOG_TAG + ".alarm", "Alarm controls are not enabled."); + } + + } else if (intent.getAction().equals(ALARM_DONE_ACTION)) { + + Log.d(LOG_TAG + ".alarm", "Alarm done event received."); + + // only take action if alarm controls are enabled + if (mStateManager.getPreference().getBoolean("pref_alarm_controls", + false)) { + Log.d(mStateManager.getPreference() + ".alarm", + "alarm is over, cleaning up"); + mStateManager.setAlarmFiring(false); + + if (mStateManager.getCoverClosed()) { + Intent mIntent = new Intent(localContext, CoreService.class); + mIntent.putExtra(CoreApp.CS_EXTRA_TASK, + CoreApp.CS_TASK_LAUNCH_ACTIVITY); + mStateManager.sendToCoreService(mIntent); + } + } + } else if (intent.getAction().equals( + TelephonyManager.ACTION_PHONE_STATE_CHANGED)) { + + if (mStateManager.getPreference().getBoolean("pref_phone_controls", + false)) { + String state = intent + .getStringExtra(TelephonyManager.EXTRA_STATE); + Log.d(LOG_TAG + ".phone", "phone state changed to " + state); + if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) { + Intent mIntent; + mStateManager.setPhoneRinging(true); + mStateManager + .setCallFrom(intent + .getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER)); + Log.d(LOG_TAG, "call from " + mStateManager.getCallFrom()); + mIntent = new Intent(localContext, CoreService.class); + mIntent.putExtra(CoreApp.CS_EXTRA_TASK, + CoreApp.CS_TASK_INCOMMING_CALL); + mStateManager.sendToCoreService(mIntent); + } else if (state.equals(TelephonyManager.EXTRA_STATE_IDLE)) { + Intent mIntent; + mStateManager.setPhoneRinging(false); + Log.d(LOG_TAG, "call is over, cleaning up"); + if (mStateManager.getCoverClosed()) { + mIntent = new Intent(localContext, CoreService.class); + mIntent.putExtra(CoreApp.CS_EXTRA_TASK, + CoreApp.CS_TASK_LAUNCH_ACTIVITY); + mStateManager.sendToCoreService(mIntent); + } + } else if (state.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) { + } + } else { + Log.d(LOG_TAG + ".phone", "phone controls are not enabled"); + } + } else if (intent.getAction().equals(mStateManager.getActionCover())) { + int state = intent.getIntExtra(EXTRA_LID_STATE, LID_ABSENT); + Log.d(LOG_TAG + ".cover", "cover state changed to " + state); + if (state == LID_CLOSED) { + Log.d(LOG_TAG + ".cover", + "Cover is close, enable Default Activity."); + mStateManager.setCoverClosed(true); + Intent mIntent = new Intent(localContext, CoreService.class); + mIntent.putExtra(CoreApp.CS_EXTRA_TASK, + CoreApp.CS_TASK_LAUNCH_ACTIVITY); + mStateManager.sendToCoreService(mIntent); + } else if (state == LID_OPEN) { + // Log.d(LOG_TAG + ".cover", + // "Cover is open, stopping Default Activity."); + mStateManager.setCoverClosed(false); + // mStateManager.freeDevice(); + Log.d(LOG_TAG + ".screen", "Cover is open, send to background."); + Intent stbDAIntent = new Intent( + CoreApp.DA_ACTION_SEND_TO_BACKGROUND); + LocalBroadcastManager.getInstance(localContext) + .sendBroadcastSync(stbDAIntent); + Intent mIntent = new Intent(localContext, CoreService.class); + mIntent.putExtra(CoreApp.CS_EXTRA_TASK, + CoreApp.CS_TASK_WAKEUP_DEVICE); + mStateManager.sendToCoreService(mIntent); + } + + } else if (intent.getAction().equals(TORCH_STATE_CHANGED)) { + if (mStateManager.getPreference().getBoolean("pref_flash_controls", + false)) { + Log.d(LOG_TAG + ".torch", "torch state changed"); + Intent mIntent = new Intent(localContext, CoreService.class); + mIntent.putExtra(CoreApp.CS_EXTRA_TASK, + CoreApp.CS_TASK_TORCH_STATE); + if (intent.getIntExtra("state", 0) != 0) { + mIntent.putExtra(CoreApp.CS_EXTRA_STATE, true); + } else { + mIntent.putExtra(CoreApp.CS_EXTRA_STATE, false); + } + mStateManager.sendToCoreService(mIntent); + } else { + Log.d(LOG_TAG + ".torch", "torch controls are not enabled."); + } + + } else if (intent.getAction().equals(Intent.ACTION_HEADSET_PLUG)) { + int state = intent.getExtras().getInt("state"); + Log.d(LOG_TAG + ".headset", "headset is " + + (state == 0 ? "gone" : "here") + "!"); + Intent mIntent = new Intent(localContext, CoreService.class); + mIntent.putExtra(CoreApp.CS_EXTRA_TASK, + CoreApp.CS_TASK_HEADSET_PLUG); + mStateManager.sendToCoreService(mIntent); + + } else if (intent.getAction().equals("org.durka.hallmonitor.debug")) { + Log.d(LOG_TAG + "", "received debug intent"); + // test intent to show/hide a notification + boolean showhide = false; + switch (intent.getIntExtra("notif", 0)) { + case 1: + showhide = true; + break; + case 2: + showhide = false; + break; + } + if (showhide) { + Notification.Builder mBuilder = new Notification.Builder( + localContext).setSmallIcon(R.drawable.ic_launcher) + .setContentTitle("Hall Monitor") + .setContentText("Debugging is fun!"); + + NotificationManager mNotificationManager = (NotificationManager) localContext + .getSystemService(Context.NOTIFICATION_SERVICE); + mNotificationManager.notify(42, mBuilder.build()); + } else { + NotificationManager mNotificationManager = (NotificationManager) localContext + .getSystemService(Context.NOTIFICATION_SERVICE); + mNotificationManager.cancel(42); + } + } + mStateManager.releaseCPUGlobal(); + } +} \ No newline at end of file diff --git a/src/org/durka/hallmonitor/CoreService.java b/src/org/durka/hallmonitor/CoreService.java new file mode 100644 index 0000000..cbd507a --- /dev/null +++ b/src/org/durka/hallmonitor/CoreService.java @@ -0,0 +1,537 @@ +/* Copyright 2013 Alex Burka + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.durka.hallmonitor; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import android.app.ActivityManager; +import android.app.Service; +import android.app.admin.DevicePolicyManager; +import android.content.Context; +import android.content.ContextWrapper; +import android.content.Intent; +import android.os.Build; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.PowerManager; +import android.os.Process; +import android.os.SystemClock; +import android.os.UserHandle; +import android.support.v4.content.LocalBroadcastManager; +import android.util.Log; +import android.view.KeyEvent; +import eu.chainfire.libsuperuser.Shell; + +public class CoreService extends Service { + private final String LOG_TAG = "Hall.CS"; + + private CoreStateManager mStateManager; + + private Looper mTouchCoverLooper; + private TouchCoverHandler mTouchCoverHandler; + private Boolean lastTouchCoverRequest; + private LocalBroadcastManager mLocalBroadcastManager; + private CoreService localCoreService; + private Method startActivityAsUser; + private Intent launchDefaultActivity; + private UserHandle mUserHandle; + + @Override + public void onCreate() { + Log.d(LOG_TAG + ".oC", "Core service creating"); + localCoreService = this; + + mStateManager = ((CoreApp) getApplicationContext()).getStateManager(); + + Log.d(LOG_TAG + ".oC", "Register special actions"); + mStateManager.registerCoreService(this); + + mStateManager.registerCoreReceiver(); + + mLocalBroadcastManager = LocalBroadcastManager.getInstance(this); + + HandlerThread thread = new HandlerThread("ServiceStartArguments", + Process.THREAD_PRIORITY_BACKGROUND); + thread.start(); + + // Get the HandlerThread's Looper and use it for our Handler + mTouchCoverLooper = thread.getLooper(); + mTouchCoverHandler = new TouchCoverHandler(mTouchCoverLooper); + lastTouchCoverRequest = mStateManager.getCoverClosed(); + + try { + startActivityAsUser = ((ContextWrapper) this).getClass().getMethod( + "startActivityAsUser", Intent.class, UserHandle.class); + Log.d(LOG_TAG, "startActivityAsUser registred"); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } + + launchDefaultActivity = new Intent(localCoreService, + DefaultActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_NO_ANIMATION + | Intent.FLAG_ACTIVITY_CLEAR_TOP + | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + + mUserHandle = android.os.Process.myUserHandle(); + } + + @Override + public IBinder onBind(Intent intent) { + // We don't provide binding, so return null + return null; + } + + @Override + public void onDestroy() { + mStateManager.unregisterCoreReceiver(); + mStateManager.unregisterCoreService(); + + Log.d(LOG_TAG + ".oD", "Core service stopped"); + + super.onDestroy(); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + if (!mStateManager.getMainLaunched() + && mStateManager.getPreference().getBoolean("pref_enabled", + false)) { + Message msg = Message.obtain(); + msg.arg1 = startId; + msg.what = CoreApp.CS_TASK_MAINLAUNCH; + ServiceThread svcThread = new ServiceThread(msg); + svcThread.start(); + } + + if (intent != null && intent.hasExtra(CoreApp.CS_EXTRA_TASK)) { + int requestedTaskMode = intent + .getIntExtra(CoreApp.CS_EXTRA_TASK, 0); + if (requestedTaskMode > 0) { + int msgArg2 = 0; + switch (requestedTaskMode) { + case CoreApp.CS_TASK_CHANGE_TOUCHCOVER: + boolean sendTouchCoverRequest = intent.getBooleanExtra( + CoreApp.CS_EXTRA_STATE, false); + if (sendTouchCoverRequest != lastTouchCoverRequest) { + mStateManager.acquireCPUGlobal(); + lastTouchCoverRequest = sendTouchCoverRequest; + Message msgTCH = mTouchCoverHandler.obtainMessage(); + msgTCH.arg1 = startId; + if (sendTouchCoverRequest) { + msgTCH.arg2 = 1; + } else { + msgTCH.arg2 = 0; + } + mTouchCoverHandler.sendMessage(msgTCH); + } + return START_STICKY; + case CoreApp.CS_TASK_AUTO_BLACKSCREEN: + if (mStateManager.getInActivity()) { + Log.d(LOG_TAG + ".oSC", + "Blackscreen requested canceled during activity"); + return START_STICKY; + } else if (mStateManager.getBlackScreenTime() > 0) { + Log.d(LOG_TAG + ".oSC", "Blackscreen already requested"); + return START_STICKY; + } + break; + case CoreApp.CS_TASK_LAUNCH_ACTIVITY: + mStateManager.acquireCPUGlobal(); + if (intent.getBooleanExtra(CoreApp.CS_EXTRA_STATE, false)) { + msgArg2 = 1; + } + break; + case CoreApp.CS_TASK_TORCH_STATE: + if (intent.getBooleanExtra(CoreApp.CS_EXTRA_STATE, false)) { + msgArg2 = 1; + } + break; + } + Log.d(LOG_TAG + ".oSC", "Request starting: " + + requestedTaskMode); + Message msg = Message.obtain(); + msg.arg1 = startId; + msg.arg2 = msgArg2; + msg.what = requestedTaskMode; + ServiceThread svcThread = new ServiceThread(msg); + svcThread.start(); + } + } + // If we get killed, after returning from here, restart + return START_STICKY; + } + + private final class TouchCoverHandler extends Handler { + public TouchCoverHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + Boolean enable = (msg.arg2 == 1); + // if we are running in root enabled mode then lets up the + // sensitivity on the view screen + // so we can use the screen through the window + if (mStateManager.getRootApp()) { + if (enable) { + Log.d(LOG_TAG + ".enableCoverTouch", + "We're root enabled so lets boost the sensitivity..."); + if (Build.DEVICE.equals(CoreApp.DEV_SERRANO_LTE_CM10) + || Build.DEVICE + .equals(CoreApp.DEV_SERRANO_LTE_CM11) + || Build.DEVICE.equals(CoreApp.DEV_SERRANO_DS_CM10) + || Build.DEVICE.equals(CoreApp.DEV_SERRANO_DS_CM11) + || Build.DEVICE.equals(CoreApp.DEV_SERRANO_3G_CM11)) { + Shell.SU.run(new String[] { + "echo module_on_master > /sys/class/sec/tsp/cmd && cat /sys/class/sec/tsp/cmd_result", + "echo clear_cover_mode,3 > /sys/class/sec/tsp/cmd && cat /sys/class/sec/tsp/cmd_result" }); + } else { // others devices + Shell.SU.run(new String[] { "echo clear_cover_mode,1 > /sys/class/sec/tsp/cmd" }); + } + Log.d(LOG_TAG + ".enableCoverTouch", + "...Sensitivity boosted, hold onto your hats!"); + } else { + Log.d(LOG_TAG + ".enableCoverTouch", + "We're root enabled so lets revert the sensitivity..."); + Shell.SU.run(new String[] { "echo clear_cover_mode,0 > /sys/class/sec/tsp/cmd && cat /sys/class/sec/tsp/cmd_result" }); + Log.d(LOG_TAG + ".enableCoverTouch", + "...Sensitivity reverted, sanity is restored!"); + } + } + mStateManager.releaseCPUGlobal(); + } + } + + private class ServiceThread extends Thread { + private final Message msg; + private Message internalMsg; + + public ServiceThread(Message msgSend) { + super(); + this.msg = msgSend; + } + + @Override + public void run() { + runCustom(msg); + } + + public void runCustom(Message msg) { + Log.d(LOG_TAG + ".handler", "Thread " + msg.arg1 + ": started"); + + switch (msg.what) { + case CoreApp.CS_TASK_TORCH_STATE: + Intent torchDAIntent = new Intent( + CoreApp.DA_ACTION_TORCH_STATE_CHANGED); + if (msg.arg2 == 1) { + mStateManager.setTorchOn(true); + torchDAIntent.putExtra(CoreApp.DA_EXTRA_STATE, true); + if (mStateManager.getCoverClosed()) { + bringDefaultActivityToFront(true); + } + } else { + mStateManager.setTorchOn(false); + torchDAIntent.putExtra(CoreApp.DA_EXTRA_STATE, false); + if (mStateManager.getCoverClosed()) { + bringDefaultActivityToFront(false); + } + } + mLocalBroadcastManager.sendBroadcastSync(torchDAIntent); + break; + case CoreApp.CS_TASK_TORCH_TOGGLE: + if (mStateManager.getPreference().getBoolean( + "pref_flash_controls", false)) { + Intent intent = new Intent(CoreReceiver.TOGGLE_FLASHLIGHT); + intent.putExtra("strobe", false); + intent.putExtra("period", 100); + intent.putExtra("bright", false); + sendBroadcastAsUser(intent, mUserHandle); + } else if (mStateManager.getPreference().getBoolean( + "pref_flash_controls_alternative", false)) { + if (!mStateManager.getTorchOn()) { + mStateManager.turnOnFlash(); + internalMsg = msg; + internalMsg.what = CoreApp.CS_TASK_TORCH_STATE; + internalMsg.arg2 = 1; + runCustom(internalMsg); + } else { + mStateManager.turnOffFlash(); + internalMsg = msg; + internalMsg.what = CoreApp.CS_TASK_TORCH_STATE; + internalMsg.arg2 = 0; + runCustom(internalMsg); + } + } + break; + case CoreApp.CS_TASK_HEADSET_PLUG: + Intent headSetIntent = new Intent( + CoreApp.DA_ACTION_WIDGET_REFRESH); + mLocalBroadcastManager.sendBroadcastSync(headSetIntent); + if (mStateManager.getCoverClosed()) { + bringDefaultActivityToFront(false); + } + break; + case CoreApp.CS_TASK_HANGUP_CALL: + Log.d(LOG_TAG + ".handler", "Thread " + msg.arg1 + + ": hanging up! goodbye"); + + KeyEvent keyHangup = new KeyEvent(KeyEvent.ACTION_UP, + KeyEvent.KEYCODE_HEADSETHOOK); + keyHangup = KeyEvent.changeTimeRepeat(keyHangup, + System.currentTimeMillis(), 1, keyHangup.getFlags() + | KeyEvent.FLAG_LONG_PRESS); + keyHangup = KeyEvent.changeFlags(keyHangup, + keyHangup.getFlags() | KeyEvent.FLAG_LONG_PRESS); + Intent pressHangUp = new Intent(Intent.ACTION_MEDIA_BUTTON); + pressHangUp.putExtra(Intent.EXTRA_KEY_EVENT, keyHangup); + sendOrderedBroadcast(pressHangUp, + "android.permission.CALL_PRIVILEGED"); + break; + case CoreApp.CS_TASK_PICKUP_CALL: + Log.d(LOG_TAG + ".handler", "Thread " + msg.arg1 + + ": picking up! hello"); + Intent pressPickupCall = new Intent(Intent.ACTION_MEDIA_BUTTON); + pressPickupCall.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent( + KeyEvent.ACTION_UP, KeyEvent.KEYCODE_HEADSETHOOK)); + sendOrderedBroadcast(pressPickupCall, + "android.permission.CALL_PRIVILEGED"); + break; + case CoreApp.CS_TASK_INCOMMING_CALL: + mStateManager.acquireCPUDA(); + wait_package_front_launched(CoreApp.PACKAGE_PHONE_APP); + if (mStateManager.getCoverClosed()) { + Log.d(LOG_TAG + ".handler", "Thread " + msg.arg1 + + ": the screen is closed. screen my calls"); + + bringDefaultActivityToFront(true); + } + break; + case CoreApp.CS_TASK_SNOOZE_ALARM: + // Broadcast alarm snooze event + Intent alarmSnooze = new Intent( + CoreReceiver.ALARM_SNOOZE_ACTION); + sendBroadcastAsUser(alarmSnooze, mUserHandle); + break; + case CoreApp.CS_TASK_DISMISS_ALARM: + // Broadcast alarm Dismiss event + Intent alarmDismiss = new Intent( + CoreReceiver.ALARM_DISMISS_ACTION); + sendBroadcastAsUser(alarmDismiss, mUserHandle); + break; + case CoreApp.CS_TASK_INCOMMING_ALARM: + mStateManager.acquireCPUDA(); + wait_package_front_launched(CoreApp.PACKAGE_ALARM_APP); + if (mStateManager.getCoverClosed()) { + Log.d(LOG_TAG + ".handler", "Thread " + msg.arg1 + + ": the screen is closed. screen alarm"); + + bringDefaultActivityToFront(true); + } + break; + case CoreApp.CS_TASK_LAUNCH_ACTIVITY: + mStateManager.acquireCPUDA(); + boolean noBlackScreen = false; + if (msg.arg2 == 1) { + noBlackScreen = true; + } + Log.d(LOG_TAG + ".handler", "Thread " + msg.arg1 + + ": Launch activity / " + noBlackScreen); + bringDefaultActivityToFront(noBlackScreen); + mStateManager.releaseCPUGlobal(); + break; + case CoreApp.CS_TASK_AUTO_BLACKSCREEN: + // already request running + if (mStateManager.getBlackScreenTime() > 0) { + Log.d(LOG_TAG + ".handler", "Thread " + msg.arg1 + + ": Blackscreen already requested"); + break; + } + mStateManager.setBlackScreenTime(System.currentTimeMillis() + + mStateManager.getPreference().getInt("pref_delay", + 10000)); + Log.d(LOG_TAG + ".handler", + "Thread " + msg.arg1 + ": Blackscreen time set to: " + + mStateManager.getBlackScreenTime()); + while (System.currentTimeMillis() < mStateManager + .getBlackScreenTime()) { + try { + Thread.sleep(100); + } catch (InterruptedException e1) { + } + } + if (mStateManager.getBlackScreenTime() > 0) { + Log.d(LOG_TAG + ".handler", + "Thread " + msg.arg1 + ": Launch blackscreen at: " + + mStateManager.getBlackScreenTime()); + launchBlackScreen(); + mStateManager.setBlackScreenTime(0); + } else { + Log.d(LOG_TAG + ".handler", "Thread " + msg.arg1 + + ": Blackscreen canceled"); + } + break; + case CoreApp.CS_TASK_WAKEUP_DEVICE: + Log.d(LOG_TAG + ".handler", "Thread " + msg.arg1 + + ": Launch wakeup"); + wakeUpDevice(); + break; + case CoreApp.CS_TASK_MAINLAUNCH: + if (!mStateManager.getMainLaunched()) { + mStateManager.setMainLaunched(true); + mStateManager.startServices(); + Log.d(LOG_TAG + ".handler", "Thread " + msg.arg1 + + ": Mainthread launched"); + while (mStateManager.getMainLaunched() + && mStateManager.getPreference().getBoolean( + "pref_enabled", false)) { + try { + Thread.sleep(10000); + } catch (InterruptedException e1) { + } + } + mStateManager.setMainLaunched(false); + stopSelf(); + Log.d(LOG_TAG + ".handler", "Thread " + msg.arg1 + + ": Mainthread stopped"); + Log.d(LOG_TAG + ".handler", "Thread " + msg.arg1 + + ": Core Service stopping"); + } else { + Log.d(LOG_TAG + ".handler", "Thread " + msg.arg1 + + ": Mainthread already launched"); + } + break; + } + + Log.d(LOG_TAG + ".handler", "Thread " + msg.arg1 + ": ended"); + // Stop the service using the startId, so that we don't stop + // the service in the middle of handling another job + } + + private void wait_package_front_launched(String pacakgeName) { + Log.d(LOG_TAG + ".wpl", "Wait launch of " + pacakgeName); + ActivityManager am = (ActivityManager) localCoreService + .getSystemService(Context.ACTIVITY_SERVICE); + long maxWaitTime = System.currentTimeMillis() + 10 * 1000; + while (System.currentTimeMillis() < maxWaitTime) { + // The first in the list of RunningTasks is always the + // foreground task. + if (am.getRunningTasks(1).get(0).topActivity.getPackageName() + .equalsIgnoreCase(pacakgeName)) { + Log.d(LOG_TAG + ".wpl", pacakgeName + " detected"); + break; + } + try { + Thread.sleep(100); + } catch (InterruptedException e1) { + } + } + } + + private void launchBlackScreen() { + if (mStateManager.getCoverClosed()) { + Log.d(LOG_TAG + ".lBS", "Cover closed."); + if (mStateManager.getLockMode()) { + final DevicePolicyManager dpm = (DevicePolicyManager) localCoreService + .getSystemService(Context.DEVICE_POLICY_SERVICE); + Log.d(LOG_TAG + ".lBS", "Lock now."); + dpm.lockNow(); + Intent freeScreenDAIntent = new Intent( + CoreApp.DA_ACTION_FREE_SCREEN); + mLocalBroadcastManager + .sendBroadcastSync(freeScreenDAIntent); + } else if (mStateManager.getOsPowerManagement()) { + Log.d(LOG_TAG + ".lBS", "OS must manage screen off."); + Intent freeScreenDAIntent = new Intent( + CoreApp.DA_ACTION_FREE_SCREEN); + mLocalBroadcastManager + .sendBroadcastSync(freeScreenDAIntent); + } else if (mStateManager.getInternalPowerManagement()) { + if (mStateManager.getPowerManager().isScreenOn()) { + Log.d(LOG_TAG + ".lBS", "Go to sleep now."); + mStateManager.getPowerManager().goToSleep( + SystemClock.uptimeMillis()); + } else { + Log.d(LOG_TAG + ".lBS", "Screen already off."); + } + } + } else { + Log.d(LOG_TAG + ".lBS", "Cover open???."); + } + } + + private void wakeUpDevice() { + if (mStateManager.getInternalPowerManagement()) { + if (!mStateManager.getPowerManager().isScreenOn()) { + Log.d(LOG_TAG + ".wUD", "WakeUp device."); + mStateManager.getPowerManager().wakeUp( + SystemClock.uptimeMillis()); + } else { + Log.d(LOG_TAG + ".wUD", "Screen already on."); + } + } else { + // FIXME Would be nice to remove the deprecated FULL_WAKE_LOCK + // if possible + Log.d(LOG_TAG + ".wUD", "aww why can't I hit snooze"); + @SuppressWarnings("deprecation") + PowerManager.WakeLock wl = mStateManager.getPowerManager() + .newWakeLock( + PowerManager.FULL_WAKE_LOCK + | PowerManager.ACQUIRE_CAUSES_WAKEUP, + localCoreService.getString(R.string.app_name)); + wl.acquire(); + wl.release(); + } + } + + private void bringDefaultActivityToFront(boolean noBlackScreen) { + + Log.d(LOG_TAG + ".bDATF", "Launching default activity"); + mStateManager.acquireCPUDA(); + + if (noBlackScreen) { + mStateManager.setBlackScreenTime(0); + } + + if (startActivityAsUser != null) { + try { + startActivityAsUser.invoke(localCoreService, + launchDefaultActivity, mUserHandle); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + } else { + Log.w(LOG_TAG, "No startActivityAsUser registred"); + } + + Log.d(LOG_TAG + ".bDATF", "Started activity."); + + if (!noBlackScreen) { + // step 2: wait for the delay period and turn the screen off + internalMsg = msg; + internalMsg.what = CoreApp.CS_TASK_AUTO_BLACKSCREEN; + this.runCustom(internalMsg); + } + } + } +} diff --git a/src/org/durka/hallmonitor/CoreStateManager.java b/src/org/durka/hallmonitor/CoreStateManager.java new file mode 100644 index 0000000..94a1d2c --- /dev/null +++ b/src/org/durka/hallmonitor/CoreStateManager.java @@ -0,0 +1,848 @@ +/* Copyright 2013 Alex Burka + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.durka.hallmonitor; + +import java.io.File; +import java.io.FileNotFoundException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Scanner; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.atomic.AtomicInteger; + +import android.app.ActivityManager; +import android.app.ActivityManager.RunningServiceInfo; +import android.app.admin.DevicePolicyManager; +import android.appwidget.AppWidgetManager; +import android.content.ComponentName; +import android.content.Context; +import android.content.ContextWrapper; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.hardware.Camera; +import android.hardware.Camera.Parameters; +import android.media.AudioManager; +import android.os.AsyncTask; +import android.os.PowerManager; +import android.os.PowerManager.WakeLock; +import android.os.SystemClock; +import android.os.UserHandle; +import android.preference.PreferenceManager; +import android.support.v4.content.LocalBroadcastManager; +import android.telephony.TelephonyManager; +import android.util.Log; +import eu.chainfire.libsuperuser.Shell; + +public class CoreStateManager { + private final String LOG_TAG = "Hall.CSM"; + + private static Context mAppContext; + private static boolean init = false; + + // All we need for alternative torch + private Camera camera; + // private final boolean flashIsOn = false; + private boolean deviceHasFlash; + + // Class that handles interaction with 3rd party App Widgets + public HMAppWidgetManager hmAppWidgetManager; + + private DefaultActivity defaultActivity; + private Configuration configurationActivity; + + private final SharedPreferences preference_all; + + private final boolean systemApp; + private boolean adminApp; + private boolean rootApp; + private boolean osPowerManagement; + private boolean internalPowerManagement; + private final boolean hardwareAccelerated; + + // audio manager to detect media state + private AudioManager audioManager; + + private boolean lockMode; + + private boolean notification_settings_ongoing = false; + private boolean widget_settings_ongoing = false; + + // states for alarm and phone + private boolean alarm_firing = false; + private boolean phone_ringing = false; + private boolean torch_on = false; + private boolean camera_up = false; + private String call_from = ""; + private boolean cover_closed = false; + private boolean forceCheckCoverState = false; + + private boolean mainLaunched = false; + private boolean defaultActivityStarting = false; + + private CoreReceiver mCoreReceiver; + private CoreService mCoreService; + private Method startCoreServiceAsUser; + + private static long blackscreen_time = 0; + + private String actionCover = CoreReceiver.ACTION_LID_STATE_CHANGED; + + private final PowerManager mPowerManager; + private final WakeLock daPartialWakeLock; + private final WakeLock globalPartialWakeLock; + private int globalPartialWakeLockCount; + + private static AtomicInteger idCounter = new AtomicInteger(); + + CoreStateManager(Context context) { + mAppContext = context; + mPowerManager = (PowerManager) mAppContext + .getSystemService(Context.POWER_SERVICE); + daPartialWakeLock = mPowerManager.newWakeLock( + PowerManager.PARTIAL_WAKE_LOCK, "CoreStateManager"); + daPartialWakeLock.setReferenceCounted(false); + globalPartialWakeLock = mPowerManager.newWakeLock( + PowerManager.PARTIAL_WAKE_LOCK, "CoreReceiver"); + globalPartialWakeLock.setReferenceCounted(true); + + preference_all = PreferenceManager + .getDefaultSharedPreferences(mAppContext); + + // Enable access to sleep mode + systemApp = (mAppContext.getApplicationInfo().flags & (ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0; + if (systemApp) { + Log.d(LOG_TAG, "We are a system app."); + } else { + Log.d(LOG_TAG, "We are not a system app."); + preference_all.edit() + .putBoolean("pref_internal_power_management", false) + .commit(); + } + + refreshAdminApp(); + refreshRootApp(); + + refreshLockMode(); + refreshOsPowerManagement(); + refreshInternalPowerManagement(); + + refreshInternalService(); + + if (preference_all.getBoolean("pref_proximity", false)) { + forceCheckCoverState = true; + } + + hmAppWidgetManager = new HMAppWidgetManager(this); + + if (preference_all.getBoolean("pref_default_widget", false)) { + int widgetId = preference_all.getInt("default_widget_id", -1); + if (widgetId == -1) { + registerWidget("default"); + } else { + createWidget("default"); + } + } + + if (preference_all.getBoolean("pref_media_widget", false)) { + audioManager = (AudioManager) mAppContext + .getSystemService(Context.AUDIO_SERVICE); + + int widgetId = preference_all.getInt("media_widget_id", -1); + if (widgetId == -1) { + registerWidget("media"); + } else { + createWidget("media"); + } + } + + this.hardwareAccelerated = preference_all.getBoolean( + "pref_hardwareAccelerated", false); + + // we might have missed a phone-state revelation + phone_ringing = ((TelephonyManager) mAppContext + .getSystemService(Context.TELEPHONY_SERVICE)).getCallState() == TelephonyManager.CALL_STATE_RINGING; + // we might have missed an alarm alert + // TODO: find a way + // alarm_firing = + // ((TelephonyManager) + // mAppContext.getSystemService(Context.TELEPHONY_SERVICE)).getCallState() + // == TelephonyManager.CALL_STATE_RINGING; + Intent stateIntent = mAppContext.registerReceiver(null, + new IntentFilter(CoreReceiver.TORCH_STATE_CHANGED)); + torch_on = stateIntent != null + && stateIntent.getIntExtra("state", 0) != 0; + + init = true; + } + + public static boolean getInitialized() { + return init; + } + + public static Context getContext() { + return mAppContext; + } + + public boolean getPhoneRinging() { + return phone_ringing; + } + + public void setPhoneRinging(boolean enable) { + phone_ringing = enable; + } + + public boolean getAlarmFiring() { + return alarm_firing; + } + + public void setAlarmFiring(boolean enable) { + alarm_firing = enable; + } + + public boolean getDefaultActivityStarting() { + return defaultActivityStarting; + } + + public void setDefaultActivityStarting(boolean enable) { + defaultActivityStarting = enable; + } + + public boolean getTorchOn() { + return torch_on; + } + + public void setTorchOn(boolean enable) { + torch_on = enable; + } + + public boolean getCameraUp() { + return camera_up; + } + + public void setCameraUp(boolean enable) { + camera_up = enable; + } + + public boolean getCoverClosed() { + return getCoverClosed(forceCheckCoverState); + } + + public boolean getCoverClosed(boolean forceCheck) { + if (forceCheck) { + String status = ""; + try { + Scanner sc = new Scanner(new File( + mAppContext.getString(R.string.hall_file))); + status = sc.nextLine(); + sc.close(); + } catch (FileNotFoundException e) { + Log.e(mAppContext.getString(R.string.app_name), + "Hall effect sensor device file not found!"); + } + boolean isClosed = (status.compareTo("CLOSE") == 0); + Log.d(LOG_TAG, "Cover closed state is: " + isClosed); + return isClosed; + } else { + Log.d(LOG_TAG, "Cover closed state is: " + cover_closed); + return cover_closed; + } + } + + public void setCoverClosed(boolean enable) { + cover_closed = enable; + } + + public boolean getMainLaunched() { + return mainLaunched; + } + + public void setMainLaunched(boolean enable) { + mainLaunched = enable; + } + + public boolean getOsPowerManagement() { + return osPowerManagement; + } + + public void refreshOsPowerManagement() { + osPowerManagement = preference_all.getBoolean( + "pref_os_power_management", false); + } + + public boolean getInternalPowerManagement() { + return internalPowerManagement; + } + + public void refreshInternalPowerManagement() { + internalPowerManagement = preference_all.getBoolean( + "pref_internal_power_management", false); + } + + public PowerManager getPowerManager() { + return mPowerManager; + } + + public String getActionCover() { + return actionCover; + } + + public void setActionCover(String mString) { + actionCover = mString; + } + + public boolean getWidgetSettingsOngoing() { + return widget_settings_ongoing; + } + + public void setWidgetSettingsOngoing(boolean enable) { + widget_settings_ongoing = enable; + } + + public boolean getNotificationSettingsOngoing() { + return notification_settings_ongoing; + } + + public void setNotificationSettingsOngoing(boolean enable) { + notification_settings_ongoing = enable; + } + + public boolean getSystemApp() { + return systemApp; + } + + public boolean getAdminApp() { + return adminApp; + } + + public void refreshAdminApp() { + final DevicePolicyManager dpm = (DevicePolicyManager) mAppContext + .getSystemService(Context.DEVICE_POLICY_SERVICE); + ComponentName me = new ComponentName(mAppContext, AdminReceiver.class); + adminApp = dpm.isAdminActive(me); + if (adminApp) { + Log.d(LOG_TAG, "We are an admin."); + } else { + Log.d(LOG_TAG, "We are not an admin so cannot do anything."); + } + refreshLockMode(); + } + + public boolean getRootApp() { + return rootApp; + } + + public void refreshRootApp() { + if (preference_all.getBoolean("pref_runasroot", false)) { + AsyncSuAvailable localSuAvailable = new AsyncSuAvailable(); + boolean rootAppResult = false; + try { + rootAppResult = localSuAvailable.execute().get(); + } catch (InterruptedException e) { + } catch (ExecutionException e) { + } + rootApp = rootAppResult; + } else { + rootApp = false; + preference_all.edit().putBoolean("pref_runasroot", false).commit(); + } + if (rootApp) { + Log.d(LOG_TAG, "We are root."); + } else { + Log.d(LOG_TAG, "We are not root."); + } + } + + public void refreshInternalService() { + if (preference_all.getBoolean("pref_internalservice", false)) { + actionCover = CoreReceiver.ACTION_INTERNAL_LID_STATE_CHANGED; + } else { + actionCover = CoreReceiver.ACTION_LID_STATE_CHANGED; + } + restartServices(); + } + + public boolean getLockMode() { + return lockMode; + } + + public void refreshLockMode() { + if (preference_all.getBoolean("pref_lockmode", false) && adminApp) { + lockMode = true; + } else { + lockMode = false; + preference_all.edit().putBoolean("pref_lockmode", false).commit(); + } + } + + public long getBlackScreenTime() { + return blackscreen_time; + } + + public void setBlackScreenTime(long time) { + blackscreen_time = time; + } + + public String getCallFrom() { + return call_from; + } + + public void setCallFrom(String num) { + call_from = num; + } + + public SharedPreferences getPreference() { + return preference_all; + } + + public void registerCoreReceiver() { + if (mCoreReceiver == null) { + /* + * HEADSET_PLUG, SCREEN_ON and SCREEN_OFF only available through + * registerReceiver function + */ + mCoreReceiver = new CoreReceiver(); + IntentFilter intfil = new IntentFilter(); + intfil.setPriority(990); + intfil.addAction(Intent.ACTION_HEADSET_PLUG); + intfil.addAction(Intent.ACTION_SCREEN_ON); + intfil.addAction(Intent.ACTION_SCREEN_OFF); + + if (preference_all.getBoolean("pref_internalservice", false)) { + IntentFilter mIntentFilter = new IntentFilter(); + mIntentFilter.addAction(getActionCover()); + LocalBroadcastManager.getInstance(mAppContext) + .registerReceiver(mCoreReceiver, mIntentFilter); + } else { + intfil.addAction(CoreReceiver.ACTION_LID_STATE_CHANGED); + } + + mAppContext.registerReceiver(mCoreReceiver, intfil); + } + } + + public void unregisterCoreReceiver() { + if (mCoreReceiver != null) { + mAppContext.unregisterReceiver(mCoreReceiver); + mCoreReceiver = null; + } + } + + public void registerCoreService(CoreService mService) { + mCoreService = mService; + try { + startCoreServiceAsUser = ((ContextWrapper) mCoreService).getClass() + .getMethod("startServiceAsUser", Intent.class, + UserHandle.class); + Log.d(LOG_TAG, "CoreService registred"); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } + } + + public void unregisterCoreService() { + mCoreService = null; + startCoreServiceAsUser = null; + Log.d(LOG_TAG, "CoreService unregistred"); + } + + public synchronized boolean setDefaultActivity( + DefaultActivity activityInstance) { + if (defaultActivity == null) { + defaultActivity = activityInstance; + return true; + } else if (activityInstance == null) { + defaultActivity = null; + return true; + } else { + Log.w(LOG_TAG, "Warning already default activity set!!!!"); + return false; + } + } + + public synchronized boolean setConfigurationActivity( + Configuration activityInstance) { + if (configurationActivity == null) { + configurationActivity = activityInstance; + return true; + } else if (activityInstance == null) { + configurationActivity = null; + return true; + } else { + Log.w(LOG_TAG, "Warning already configuration activity set!!!!"); + return false; + } + } + + public synchronized DefaultActivity getDefaultActivity() { + return defaultActivity; + } + + public synchronized Configuration getConfigurationActivity() { + return configurationActivity; + } + + public boolean getDefaultActivityRunning() { + try { + ActivityInfo[] list = mAppContext.getPackageManager() + .getPackageInfo(mAppContext.getPackageName(), + PackageManager.GET_ACTIVITIES).activities; + for (int i = 0; i < list.length; i++) { + if (list[i].name == "org.durka.hallmonitor.DefaultActivity") { + return true; + } + } + } catch (NameNotFoundException e1) { + } + return false; + } + + public boolean getConfigurationActivityRunning() { + try { + ActivityInfo[] list = mAppContext.getPackageManager() + .getPackageInfo(mAppContext.getPackageName(), + PackageManager.GET_ACTIVITIES).activities; + for (int i = 0; i < list.length; i++) { + if (list[i].name == "org.durka.hallmonitor.DefaultActivity") { + return true; + } + } + } catch (NameNotFoundException e1) { + } + return false; + } + + public void closeDefaultActivity() { + Log.w(LOG_TAG, "Send close default activity"); + setDefaultActivityStarting(false); + Intent finishDAIntent = new Intent(CoreApp.DA_ACTION_FINISH); + LocalBroadcastManager.getInstance(mAppContext).sendBroadcastSync( + finishDAIntent); + } + + public void closeConfigurationActivity() { + if (configurationActivity != null) { + configurationActivity.finish(); + } + } + + public void closeAllActivity() { + Log.w(LOG_TAG, "Try close all activity"); + closeDefaultActivity(); + closeConfigurationActivity(); + } + + public void freeDevice() { + setBlackScreenTime(0); + closeAllActivity(); + } + + public AudioManager getAudioManager() { + return audioManager; + } + + public void createWidget(String widgetType) { + int widgetId = preference_all.getInt(widgetType + "_widget_id", -1); + if (widgetId != -1) { + if (!hmAppWidgetManager.doesWidgetExist(widgetType)) { + Log.d(LOG_TAG, "creating " + widgetType + " widget with id=" + + widgetId); + Intent data = new Intent(); + data.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId); + + hmAppWidgetManager.createWidget(widgetType, data); + } + } + } + + /** + * Hand off to the HMAppWidgetManager to deal with registering new app + * widget. + * + * @param act + * The Activity to use as the context for these actions + * @param widgetType + * The type of widget (e.g. 'default', 'media', 'notification' + * etc.) + */ + public void registerWidget(String widgetType) { + + Log.d(LOG_TAG, "Register widget called for type: " + widgetType); + // hand off to the HM App Widget Manager for processing + if (widget_settings_ongoing) { + Log.d(LOG_TAG, "skipping, already inflight"); + } else { + hmAppWidgetManager.registerWidget(widgetType); + } + } + + /** + * Hand off to the HMAppWidgetManager to deal with unregistering existing + * app widget. + * + * @param act + * The Activity to use as the context for these actions + * @param widgetType + * The type of widget (e.g. 'default', 'media', 'notification' + * etc.) + */ + public void unregisterWidget(String widgetType) { + + Log.d(LOG_TAG, "unregister widget called for type: " + widgetType); + // hand off to the HM App Widget Manager for processing + hmAppWidgetManager.unregisterWidget(widgetType); + } + + public HMAppWidgetManager getHMAppWidgetManager() { + return hmAppWidgetManager; + } + + public void sendToCoreService(Intent mIntent) { + if (startCoreServiceAsUser != null) { + try { + startCoreServiceAsUser.invoke(mCoreService, mIntent, + android.os.Process.myUserHandle()); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + } else { + Log.w(LOG_TAG, "No CoreService registred"); + } + } + + /** + * Starts the HallMonitor services. + * + */ + public void startServices() { + Log.d(LOG_TAG, "Start all services called."); + + acquireCPUGlobal(); + + mAppContext.startService(new Intent(mAppContext, CoreService.class)); + if (preference_all.getBoolean("pref_internalservice", false)) { + if (preference_all.getBoolean("pref_realhall", false)) { + mAppContext.startService(new Intent(mAppContext, + ViewCoverHallService.class)); + } else if (preference_all.getBoolean("pref_proximity", false)) { + mAppContext.startService(new Intent(mAppContext, + ViewCoverProximityService.class)); + } + } + if (preference_all.getBoolean("pref_do_notifications", false)) { + mAppContext.startService(new Intent(mAppContext, + NotificationService.class)); + } + if (getCoverClosed(true)) { + Intent mIntent = new Intent(mAppContext, CoreService.class); + mIntent.putExtra(CoreApp.CS_EXTRA_TASK, + CoreApp.CS_TASK_LAUNCH_ACTIVITY); + mAppContext.startService(mIntent); + } + + releaseCPUGlobal(); + } + + /** + * Stops the HallMonitor service. + * + */ + public void stopServices() { + stopServices(false); + } + + public void stopServices(boolean override_keep_admin) { + + Log.d(LOG_TAG, "Stop all services called."); + + if (getServiceRunning(ViewCoverHallService.class)) { + mAppContext.stopService(new Intent(mAppContext, + ViewCoverHallService.class)); + } + if (getServiceRunning(ViewCoverProximityService.class)) { + mAppContext.stopService(new Intent(mAppContext, + ViewCoverProximityService.class)); + } + if (getServiceRunning(NotificationService.class)) { + mAppContext.stopService(new Intent(mAppContext, + NotificationService.class)); + } + if (getServiceRunning(CoreService.class)) { + mAppContext.stopService(new Intent(mAppContext, CoreService.class)); + } + + // Relinquish device admin (unless asked not to) + if (!override_keep_admin + && !preference_all.getBoolean("pref_keep_admin", false)) { + DevicePolicyManager dpm = (DevicePolicyManager) mAppContext + .getSystemService(Context.DEVICE_POLICY_SERVICE); + ComponentName me = new ComponentName(mAppContext, + AdminReceiver.class); + if (dpm.isAdminActive(me)) { + dpm.removeActiveAdmin(me); + } + } + } + + public void restartServices() { + stopServices(); + SystemClock.sleep(1000); + startServices(); + } + + /** + * Is the service running. + * + * @param ctx + * Application context. + * @return Is the cover closed. + */ + public boolean getServiceRunning(@SuppressWarnings("rawtypes") Class svc) { + + Log.d(LOG_TAG, "Is service running called."); + + ActivityManager manager = (ActivityManager) mAppContext + .getSystemService(Context.ACTIVITY_SERVICE); + for (RunningServiceInfo service : manager + .getRunningServices(Integer.MAX_VALUE)) { + if (svc.getName().equals(service.service.getClassName())) { + // the service is running + Log.d(LOG_TAG, "The " + svc.getName() + " is running."); + return true; + } + } + // the service must not be running + Log.d(LOG_TAG, "The " + svc.getName() + " service is NOT running."); + return false; + } + + /** + * With this non-CM users can use torch button in HallMonitor. Should + * (Hopefully) work on every device with SystemFeature FEATURE_CAMERA_FLASH + * This code has been tested on I9505 jflte with ParanoidAndroid 4.4 rc2 + */ + + // Turn On Flash + public void turnOnFlash() { + setTorchOn(true); + camera = Camera.open(); + Parameters p = camera.getParameters(); + p.setFlashMode(Parameters.FLASH_MODE_TORCH); + camera.setParameters(p); + camera.startPreview(); + Log.d(LOG_TAG, "Flash turned on!"); + } + + // Turn Off Flash + public void turnOffFlash() { + Parameters p = camera.getParameters(); + p.setFlashMode(Parameters.FLASH_MODE_OFF); + camera.setParameters(p); + camera.stopPreview(); + // Be sure to release the camera when the flash is turned off + if (camera != null) { + camera.release(); + camera = null; + Log.d(LOG_TAG, "Flash turned off and camera released!"); + } + setTorchOn(false); + } + + public boolean getDeviceHasFlash() { + deviceHasFlash = mAppContext.getPackageManager().hasSystemFeature( + PackageManager.FEATURE_CAMERA_FLASH); + return deviceHasFlash; + } + + public boolean getHardwareAccelerated() { + return hardwareAccelerated; + } + + public void requestAdmin() { + if (!adminApp && preference_all.getBoolean("pref_lockmode", false) + && configurationActivity != null) { + ComponentName me = new ComponentName(mAppContext, + AdminReceiver.class); + Log.d(LOG_TAG, "launching dpm overlay"); + mAppContext.startActivity(new Intent(getContext(), + Configuration.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_NO_ANIMATION + | Intent.FLAG_ACTIVITY_CLEAR_TOP + | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)); + Log.d(LOG_TAG, "Started configuration activity."); + Intent coup = new Intent( + DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN); + coup.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, me); + coup.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION, + mAppContext.getString(R.string.admin_excuse)); + getConfigurationActivity().startActivityForResult(coup, + CoreApp.DEVICE_ADMIN_WAITING); + } + } + + private class AsyncSuAvailable extends AsyncTask { + @Override + protected Boolean doInBackground(Boolean... params) { + return Shell.SU.available(); + } + } + + public static String createID() { + return String.valueOf(idCounter.getAndIncrement()); + } + + public void acquireCPUDA() { + daPartialWakeLock.acquire(); + } + + public void releaseCPUDA() { + if (daPartialWakeLock.isHeld()) { + daPartialWakeLock.release(); + } + } + + public void acquireCPUGlobal() { + globalPartialWakeLock.acquire(); + globalPartialWakeLockCount++; + Log.d(LOG_TAG, "globalPartialWakeLockCount=" + + globalPartialWakeLockCount); + } + + public void releaseCPUGlobal() { + if (globalPartialWakeLock.isHeld()) { + globalPartialWakeLock.release(); + globalPartialWakeLockCount--; + Log.d(LOG_TAG, "globalPartialWakeLockCount=" + + globalPartialWakeLockCount); + } + } + + public boolean getInActivity() { + if (camera_up | phone_ringing | alarm_firing) { + return true; + } else { + return false; + } + } +} diff --git a/src/org/durka/hallmonitor/DefaultActivity.java b/src/org/durka/hallmonitor/DefaultActivity.java index e1206bf..920f428 100644 --- a/src/org/durka/hallmonitor/DefaultActivity.java +++ b/src/org/durka/hallmonitor/DefaultActivity.java @@ -1,494 +1,856 @@ package org.durka.hallmonitor; +import io.github.homelocker.lib.HomeKeyLocker; + import java.text.DateFormat; import java.util.Date; -import java.util.Timer; -import java.util.TimerTask; - -import org.durka.hallmonitor.Functions.Actions; -import org.durka.hallmonitor.Functions.TorchActions; import android.app.Activity; import android.appwidget.AppWidgetHostView; import android.content.BroadcastReceiver; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.media.AudioManager; +import android.database.Cursor; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.drawable.Drawable; +import android.net.Uri; import android.os.BatteryManager; import android.os.Bundle; -import android.preference.PreferenceManager; -import android.telephony.TelephonyManager; +import android.provider.BaseColumns; +import android.provider.ContactsContract; +import android.service.notification.StatusBarNotification; +import android.support.v4.content.LocalBroadcastManager; import android.util.Log; -import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; +import android.widget.GridView; import android.widget.ImageButton; import android.widget.ImageView; -import android.widget.TextClock; import android.widget.RelativeLayout; +import android.widget.TextClock; import android.widget.TextView; -import io.github.homelocker.lib.HomeKeyLocker; - /** - * This is the activity that is displayed by default - it is displayed for the configurable delay number of milliseconds when the case is closed, - * it is also displayed when the power button is pressed when the case is already closed + * This is the activity that is displayed by default - it is displayed for the + * configurable delay number of milliseconds when the case is closed, it is also + * displayed when the power button is pressed when the case is already closed */ public class DefaultActivity extends Activity { - private HMAppWidgetManager hmAppWidgetManager = Functions.hmAppWidgetManager; - - private static boolean mDebug = false; - - public static boolean on_screen; - - // states for alarm and phone - public static boolean alarm_firing = false; - public static boolean phone_ringing = false; - public static boolean camera_up = false; - public static String call_from = ""; - - //audio manager to detect media state - private AudioManager audioManager; - - //manager for home key hack - private HomeKeyLocker homeKeyLocker; - - //Action fired when alarm goes off - public static final String ALARM_ALERT_ACTION = "com.android.deskclock.ALARM_ALERT"; - //Action to trigger snooze of the alarm - public static final String ALARM_SNOOZE_ACTION = "com.android.deskclock.ALARM_SNOOZE"; - //Action to trigger dismiss of the alarm - public static final String ALARM_DISMISS_ACTION = "com.android.deskclock.ALARM_DISMISS"; - //This action should let us know if the alarm has been killed by another app - public static final String ALARM_DONE_ACTION = "com.android.deskclock.ALARM_DONE"; - - //all the views we need - public ImageButton torchButton = null; - public ImageButton torchButton2 = null; - private ImageButton cameraButton = null; - - //we need to kill this activity when the screen opens - private final BroadcastReceiver receiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) { - - Log.d("DA.onReceive", "Screen on event received."); - - if (Functions.Is.cover_closed(context)) { - Log.d("DA.onReceive", "Cover is closed, display Default Activity."); - //easiest way to do this is actually just to invoke the close_cover action as it does what we want - Functions.Actions.close_cover(getApplicationContext()); - } else { - Log.d("DA.onReceive", "Cover is open, stopping Default Activity."); + private static final String LOG_TAG = "Hall.DA"; - // when the cover opens, the fullscreen activity goes poof - //Log.d("DA.onReceive", "Current task: " + ((ActivityManager)getSystemService(ACTIVITY_SERVICE)).getRunningTasks(1).get(0).topActivity.getPackageName()); - //moveTaskToBack(true); - finish(); - } + // all the views we need + private ImageButton torchButton = null; + private ImageButton cameraButton = null; + private ViewGroup defaultWidgetAreaVG = null; + private View mainView = null; - } else if (intent.getAction().equals(ALARM_ALERT_ACTION)) { + // manager for home key hack + private HomeKeyLocker homeKeyLocker; - Log.d("DA.onReceive", "Alarm on event received."); + private CoreStateManager mStateManager; - //only take action if alarm controls are enabled - if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean("pref_alarm_controls", false)) { + private String daId; + private BroadcastReceiver mMessageReceiver; - Log.d("DA.onReceive", "Alarm controls are enabled, taking action."); + private int allLayoutParams; - //set the alarm firing state - alarm_firing=true; + /** + * Refresh the display taking account of device and application state + */ + private void refreshDisplay() { + Log.d(LOG_TAG + daId + ".rD", "refreshing"); + + // Update all custom data and time view. + updateDateTime(); + + // if the alarm is firing then show the alarm controls, otherwise + if (mStateManager.getAlarmFiring()) { + displayAlarm(); + } else if (mStateManager.getPhoneRinging()) { + displayPhone(); + } else if (mStateManager.getCameraUp()) { + displayCamera(); + } else { + displayNormal(); + } + } - //if the cover is closed then - //we want to pop this activity up over the top of the alarm activity - //to guarantee that we need to hold off until the alarm activity is running - //a 1 second delay seems to allow this - if (Functions.Is.cover_closed(context)) { - Functions.Actions.enableCoverTouch(context, true); - Timer timer = new Timer(); - timer.schedule(new TimerTask() { - @Override - public void run() { - Intent myIntent = new Intent(getApplicationContext(),DefaultActivity.class); - myIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_CLEAR_TOP - | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); - myIntent.setAction(Intent.ACTION_MAIN); - startActivity(myIntent); + private void displayAlarm() { + // show the alarm controls + findViewById(R.id.default_content_alarm).setVisibility(View.VISIBLE); + findViewById(R.id.default_content_phone).setVisibility(View.GONE); + findViewById(R.id.default_content_normal).setVisibility(View.GONE); + findViewById(R.id.default_content_camera).setVisibility(View.GONE); + } - } - }, 1000); - } - } else { - Log.d("DA.onReceive", "Alarm controls are not enabled."); - } + private void displayPhone() { + ((TextView) findViewById(R.id.call_from)) + .setText(getString(R.string.unknown_caller)); + // show the phone controls + findViewById(R.id.default_content_alarm).setVisibility(View.GONE); + findViewById(R.id.default_content_phone).setVisibility(View.VISIBLE); + findViewById(R.id.default_content_normal).setVisibility(View.GONE); + findViewById(R.id.default_content_camera).setVisibility(View.GONE); - } else if (intent.getAction().equals(ALARM_DONE_ACTION) ) { - - Log.d("DA.onReceive", "Alarm done event received."); - - //if the alarm is turned off using the normal alarm screen this will - //ensure that we will hide the alarm controls - alarm_firing=false; - - } else if (intent.getAction().equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) { - - if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean("pref_phone_controls", false)) { - String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE); - Log.d("phone", "phone state changed to " + state); - if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) { - Functions.Events.incoming_call(context, intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER)); - Functions.Actions.choose_call_layout(getApplicationContext()); - } else { - if (state.equals(TelephonyManager.EXTRA_STATE_IDLE)) { - Functions.Events.call_finished(context); - } - } - refreshDisplay(); + ((TextView) findViewById(R.id.call_from)).setText(getContactName(this, + mStateManager.getCallFrom())); + + } + + private void displayCamera() { + findViewById(R.id.default_content_alarm).setVisibility(View.GONE); + findViewById(R.id.default_content_phone).setVisibility(View.GONE); + findViewById(R.id.default_content_normal).setVisibility(View.GONE); + findViewById(R.id.default_content_camera).setVisibility(View.VISIBLE); + } + + private void displayNormal() { + setWidgetContent(); + setBatteryIcon(); + + // normal view + findViewById(R.id.default_content_alarm).setVisibility(View.GONE); + findViewById(R.id.default_content_phone).setVisibility(View.GONE); + findViewById(R.id.default_content_normal).setVisibility(View.VISIBLE); + findViewById(R.id.default_content_camera).setVisibility(View.GONE); + } + + private void setBatteryIcon() { + if (findViewById(R.id.default_battery_picture_horizontal) != null) { + Intent battery_status = registerReceiver(null, new IntentFilter( + Intent.ACTION_BATTERY_CHANGED)); + int level = (int) (battery_status.getIntExtra( + BatteryManager.EXTRA_LEVEL, -1) + / (float) battery_status.getIntExtra( + BatteryManager.EXTRA_SCALE, -1) * 100), status = battery_status + .getIntExtra(BatteryManager.EXTRA_STATUS, -1); + if (status == BatteryManager.BATTERY_STATUS_CHARGING + || status == BatteryManager.BATTERY_STATUS_FULL) { + ((ImageView) findViewById(R.id.default_battery_picture_horizontal)) + .setImageResource(R.drawable.stat_sys_battery_charge_horizontal); + if (level > 99) { + ((TextView) findViewById(R.id.default_battery_percent)) + .setText(""); } else { - Log.d("phone", "phone controls are not enabled"); + ((TextView) findViewById(R.id.default_battery_percent)) + .setText(Integer.toString(level)); } - } else if (intent.getAction().equals("org.durka.hallmonitor.debug")) { - Log.d("DA.onReceive", "received debug intent"); - // test intent to show/hide a notification - switch (intent.getIntExtra("notif", 0)) { - case 1: - Functions.Actions.debug_notification(context, true); - break; - case 2: - Functions.Actions.debug_notification(context, false); - break; + } else { + ((ImageView) findViewById(R.id.default_battery_picture_horizontal)) + .setImageResource(R.drawable.stat_sys_battery_horizontal); + if (level > 99) { + ((TextView) findViewById(R.id.default_battery_percent)) + .setText(""); + } else { + ((TextView) findViewById(R.id.default_battery_percent)) + .setText(Integer.toString(level)); } } + ((ImageView) findViewById(R.id.default_battery_picture_horizontal)) + .getDrawable().setLevel(level); } - }; + } + private void refreshNotifications() { + if (mStateManager.getPreference().getBoolean("pref_do_notifications", + false)) { + final GridView grid = (GridView) findViewById(R.id.default_icon_container); + final NotificationAdapter adapter = (NotificationAdapter) grid + .getAdapter(); + final StatusBarNotification[] notifs = NotificationService.that + .getActiveNotifications(); + adapter.update(notifs); + runOnUiThread(new Runnable() { + @Override + public void run() { + grid.setNumColumns(notifs.length); + adapter.notifyDataSetChanged(); + } + }); + } + } - /** - * Refresh the display taking account of device and application state - */ - public void refreshDisplay() { - - if (findViewById(R.id.default_battery_picture_horizontal) != null) { - Intent battery_status = registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); - int level = (int) (battery_status.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) / (float)battery_status.getIntExtra(BatteryManager.EXTRA_SCALE, -1) * 100), - status = battery_status.getIntExtra(BatteryManager.EXTRA_STATUS, -1); - if (status == BatteryManager.BATTERY_STATUS_CHARGING || status == BatteryManager.BATTERY_STATUS_FULL) { - ((ImageView)findViewById(R.id.default_battery_picture_horizontal)).setImageResource(R.drawable.stat_sys_battery_charge_horizontal); - ((TextView)findViewById(R.id.default_battery_percent)).setText(Integer.toString(level)); - } else { - ((ImageView)findViewById(R.id.default_battery_picture_horizontal)).setImageResource(R.drawable.stat_sys_battery_horizontal); - ((TextView)findViewById(R.id.default_battery_percent)).setText(Integer.toString(level) + "%"); + private void setupNotifications() { + StatusBarNotification[] notifs = NotificationService.that + .getActiveNotifications(); + Log.d(LOG_TAG + daId + ".sN", Integer.toString(notifs.length) + + " notifications"); + GridView grid = (GridView) findViewById(R.id.default_icon_container); + grid.setNumColumns(notifs.length); + grid.setAdapter(new NotificationAdapter(this, notifs)); + } + + private void setMainLayout() { + if (mStateManager.getPreference().getBoolean("pref_layout", true)) { + setContentView(R.layout.activity_alternative); + if (mStateManager.getPreference().getBoolean( + "pref_do_notifications", true)) { + getWindow().clearFlags( + WindowManager.LayoutParams.FLAG_FULLSCREEN); + findViewById(R.id.default_battery_percent).setVisibility( + View.INVISIBLE); + findViewById(R.id.default_battery_picture_horizontal) + .setVisibility(View.INVISIBLE); } - ((ImageView)findViewById(R.id.default_battery_picture_horizontal)).getDrawable().setLevel(level); + } else { + setContentView(R.layout.activity_default); } + mainView = findViewById(R.id.default_main); + mainView.setFocusable(true); + mainView.setFocusableInTouchMode(true); + } - // we might have missed a phone-state revelation - phone_ringing = ((TelephonyManager)getSystemService(TELEPHONY_SERVICE)).getCallState() == TelephonyManager.CALL_STATE_RINGING; + private void setCallInput() { + if (mStateManager.getPreference().getBoolean( + "pref_incoming_call_input", false)) { + findViewById(R.id.swipe_call).setLongClickable(true); + findViewById(R.id.swipe_call).setOnTouchListener( + new SwipeTouchListener(this, + SwipeTouchListener.ActionMode.MODE_CALL)); + findViewById(R.id.swipe_call).setVisibility(View.VISIBLE); + Log.d(LOG_TAG + daId + ".sCI", "Call Swipe"); + } else { + findViewById(R.id.swipe_call).setVisibility(View.GONE); + Log.d(LOG_TAG + daId + ".sCI", "Call Button"); + } + } - //set the colours based on the picker values - Drawable rounded = getResources().getDrawable(R.drawable.rounded); - rounded.setColorFilter(new PorterDuffColorFilter(PreferenceManager.getDefaultSharedPreferences(this).getInt("pref_default_bgcolor", 0xFF000000), PorterDuff.Mode.MULTIPLY)); - ((RelativeLayout)findViewById(R.id.default_content)).setBackground(rounded); - ((TextClock)findViewById(R.id.default_text_clock)).setTextColor(PreferenceManager.getDefaultSharedPreferences(this).getInt("pref_default_fgcolor", 0xFFFFFFFF)); - ((TextClock)findViewById(R.id.default_text_clock_hour)).setTextColor(PreferenceManager.getDefaultSharedPreferences(this).getInt("pref_default_fgcolor", 0xFFFFFFFF)); - ((TextView)findViewById(R.id.default_text_clock_date)).setTextColor(PreferenceManager.getDefaultSharedPreferences(this).getInt("pref_default_fgcolor", 0xFFFFFFFF)); - ((TextView)findViewById(R.id.default_text_clock_date)).setText(DateFormat.getDateInstance(DateFormat.MEDIUM).format(new Date())); - - //hide or show the torch button as required - if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean("pref_flash_controls", false)) - { - torchButton.setVisibility(View.VISIBLE); + private void setAlarmInput() { + if (mStateManager.getPreference().getBoolean("pref_alarm_input", false)) { + findViewById(R.id.swipe_alarm).setLongClickable(true); + findViewById(R.id.swipe_alarm).setOnTouchListener( + new SwipeTouchListener(this, + SwipeTouchListener.ActionMode.MODE_ALARM)); + findViewById(R.id.swipe_alarm).setVisibility(View.VISIBLE); + Log.d(LOG_TAG + daId + ".sAI", "Alarm Swipe"); } else { - torchButton.setVisibility(View.INVISIBLE); + findViewById(R.id.swipe_alarm).setVisibility(View.GONE); + Log.d(LOG_TAG + daId + ".sAI", "Alarm Button"); } - - //hide or show the alternate torch button as required - if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean("pref_flash_controls_alternative", false)) - { - torchButton2.setVisibility(View.VISIBLE); + } + + // TODO simpler layout swipe (add a transparent view?) + private void setNormalInput() { + // Torch swipe/button + if ((mStateManager.getPreference().getBoolean("pref_flash_controls", + false) || mStateManager.getPreference().getBoolean( + "pref_flash_controls_alternative", false)) + && mStateManager.getPreference().getBoolean("pref_torch_input", + false)) { + findViewById(R.id.swipe_torch).setLongClickable(true); + findViewById(R.id.swipe_torch).setOnTouchListener( + new SwipeTouchListener(this, + SwipeTouchListener.ActionMode.MODE_TORCH)); + findViewById(R.id.swipe_torch).setVisibility(View.VISIBLE); + + Log.d(LOG_TAG + daId + ".sTI", "Torch Swipe"); } else { - torchButton2.setVisibility(View.INVISIBLE); + findViewById(R.id.swipe_torch).setVisibility(View.GONE); + Log.d(LOG_TAG + daId + ".sTI", "Torch Button"); } - - //hide or show the camera button as required - if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean("pref_camera_controls", false)) - { - cameraButton.setVisibility(View.VISIBLE); + + // Camera swipe/button + if (mStateManager.getPreference().getBoolean("pref_camera_controls", + false) + && mStateManager.getPreference().getBoolean( + "pref_camera_input", false)) { + findViewById(R.id.swipe_camera).setLongClickable(true); + findViewById(R.id.swipe_camera).setOnTouchListener( + new SwipeTouchListener(this, + SwipeTouchListener.ActionMode.MODE_CAMERA)); + findViewById(R.id.swipe_camera).setVisibility(View.VISIBLE); + + Log.d(LOG_TAG + daId + ".sTI", "Camera Swipe"); } else { - cameraButton.setVisibility(View.INVISIBLE); + findViewById(R.id.swipe_camera).setVisibility(View.GONE); + Log.d(LOG_TAG + daId + ".sTI", "Camera Button"); } - - //if the alarm is firing then show the alarm controls, otherwise - //if we have a media app widget and media is playing or headphones are connected then display that, otherwise - //if we have a default app widget to use then display that, if not then display our default clock screen - //(which is part of the default layout so will show anyway) - //will do this simply by setting the widgetType - String widgetType = "default"; - if (hmAppWidgetManager.doesWidgetExist("media") && (audioManager.isWiredHeadsetOn() || audioManager.isMusicActive())) { - widgetType = "media"; + } + + private void visibilityTorchButton() { + // hide or show the torch button as required + if (mStateManager.getPreference().getBoolean("pref_flash_controls", + false) + || mStateManager.getPreference().getBoolean( + "pref_flash_controls_alternative", false)) { + torchButton.setVisibility(View.VISIBLE); + } else { + torchButton.setVisibility(View.GONE); } - // reset to showing the clock, but in a second we might hide it and attach a widget - if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean("pref_datetime", false)) - { - findViewById(R.id.default_text_clock).setVisibility(View.INVISIBLE); - findViewById(R.id.default_text_clock_hour).setVisibility(View.VISIBLE); - findViewById(R.id.default_text_clock_date).setVisibility(View.VISIBLE); + } + + private void visibilityCameraButton() { + // hide or show the camera button as required + if (mStateManager.getPreference().getBoolean("pref_camera_controls", + false)) { + cameraButton.setVisibility(View.VISIBLE); } else { - findViewById(R.id.default_text_clock).setVisibility(View.VISIBLE); - findViewById(R.id.default_text_clock_hour).setVisibility(View.INVISIBLE); - findViewById(R.id.default_text_clock_date).setVisibility(View.INVISIBLE); + cameraButton.setVisibility(View.GONE); } - - ((RelativeLayout)findViewById(R.id.default_widget_area)).removeAllViews(); - - if (alarm_firing) { - // show the alarm controls - findViewById(R.id.default_content_alarm).setVisibility(View.VISIBLE); - findViewById(R.id.default_content_phone).setVisibility(View.INVISIBLE); - findViewById(R.id.default_content_normal).setVisibility(View.INVISIBLE); - findViewById(R.id.default_content_camera).setVisibility(View.INVISIBLE); - - } else if (phone_ringing) { - - // show the phone controls - findViewById(R.id.default_content_alarm).setVisibility(View.INVISIBLE); - findViewById(R.id.default_content_phone).setVisibility(View.VISIBLE); - findViewById(R.id.default_content_normal).setVisibility(View.INVISIBLE); - findViewById(R.id.default_content_camera).setVisibility(View.INVISIBLE); - - ((TextView)findViewById(R.id.call_from)).setText(Functions.Util.getContactName(this, call_from)); - - } else if (camera_up) { - - findViewById(R.id.default_content_alarm).setVisibility(View.INVISIBLE); - findViewById(R.id.default_content_phone).setVisibility(View.INVISIBLE); - findViewById(R.id.default_content_normal).setVisibility(View.INVISIBLE); - findViewById(R.id.default_content_camera).setVisibility(View.VISIBLE); + } + + private void changeColor() { + // set the colors based on the picker values + Drawable rounded = getResources().getDrawable(R.drawable.rounded); + rounded.setColorFilter(new PorterDuffColorFilter(mStateManager + .getPreference().getInt("pref_default_bgcolor", 0xFF000000), + PorterDuff.Mode.MULTIPLY)); + ((RelativeLayout) findViewById(R.id.default_content)) + .setBackground(rounded); + ((TextClock) findViewById(R.id.default_text_clock)) + .setTextColor(mStateManager.getPreference().getInt( + "pref_default_fgcolor", 0xFFFFFFFF)); + ((TextClock) findViewById(R.id.default_text_clock_hour)) + .setTextColor(mStateManager.getPreference().getInt( + "pref_default_fgcolor", 0xFFFFFFFF)); + ((TextView) findViewById(R.id.default_text_clock_date)) + .setTextColor(mStateManager.getPreference().getInt( + "pref_default_fgcolor", 0xFFFFFFFF)); + ((TextView) findViewById(R.id.default_text_fulltime_very_small)) + .setTextColor(mStateManager.getPreference().getInt( + "pref_default_fgcolor", 0xFFFFFFFF)); + } + private void changeTimeDateDisplay() { + changeTimeDateDisplay(false); + } + + private void changeTimeDateDisplay(boolean removeAll) { + if (removeAll) { + findViewById(R.id.default_text_clock).setVisibility(View.GONE); + findViewById(R.id.default_text_clock_hour).setVisibility(View.GONE); + findViewById(R.id.default_text_clock_date).setVisibility(View.GONE); } else { - //normal view - findViewById(R.id.default_content_alarm).setVisibility(View.INVISIBLE); - findViewById(R.id.default_content_phone).setVisibility(View.INVISIBLE); - findViewById(R.id.default_content_normal).setVisibility(View.VISIBLE); - findViewById(R.id.default_content_camera).setVisibility(View.INVISIBLE); - - //add the required widget based on the widgetType - if (hmAppWidgetManager.doesWidgetExist(widgetType)) { - - //get the widget - AppWidgetHostView hostView = hmAppWidgetManager.getAppWidgetHostViewByType(widgetType); - - //if the widget host view already has a parent then we need to detach it - ViewGroup parent = (ViewGroup)hostView.getParent(); - if ( parent != null) { - Log.d("DA.onCreate", "hostView had already been added to a group, detaching it."); - parent.removeView(hostView); - } - - //add the widget to the view - findViewById(R.id.default_text_clock).setVisibility(View.INVISIBLE); - findViewById(R.id.default_text_clock_hour).setVisibility(View.INVISIBLE); - findViewById(R.id.default_text_clock_date).setVisibility(View.INVISIBLE); - ((RelativeLayout)findViewById(R.id.default_widget_area)).addView(hostView); + if (mStateManager.getPreference() + .getBoolean("pref_datetime", false)) { + findViewById(R.id.default_text_clock).setVisibility(View.GONE); + findViewById(R.id.default_text_clock_hour).setVisibility( + View.VISIBLE); + findViewById(R.id.default_text_clock_date).setVisibility( + View.VISIBLE); + findViewById(R.id.default_text_fulltime_very_small) + .setVisibility(View.GONE); + } else { + findViewById(R.id.default_text_clock).setVisibility( + View.VISIBLE); + findViewById(R.id.default_text_clock_hour).setVisibility( + View.GONE); + findViewById(R.id.default_text_clock_date).setVisibility( + View.GONE); + findViewById(R.id.default_text_fulltime_very_small) + .setVisibility(View.GONE); } } } + public void updateDateTime() { + String mDate = DateFormat.getDateInstance(DateFormat.MEDIUM).format( + new Date()); + String mTime = DateFormat.getTimeInstance(DateFormat.SHORT).format( + new Date()); + + ((TextView) findViewById(R.id.default_text_fulltime_very_small)) + .setText(mTime + " " + mDate); + ((TextView) findViewById(R.id.default_text_clock_date)).setText(mDate); + } + + /** + * If we have a media app widget and media is playing or headphones are + * connected then display that, otherwise if we have a default app widget to + * use then display that, if not then display our default clock screen + * (which is part of the default layout so will show anyway) will do this + * simply by setting the widgetType + */ + @SuppressWarnings("deprecation") + public void setWidgetContent() { + if (!(mStateManager.getPreference().getBoolean("pref_media_widget", + false) || mStateManager.getPreference().getBoolean( + "pref_default_widget", false))) { + defaultWidgetAreaVG.setVisibility(View.GONE); + changeTimeDateDisplay(); + return; + } + String widgetType = "default"; + if (mStateManager.getPreference() + .getBoolean("pref_media_widget", false) + && ((mStateManager.getAudioManager().isWiredHeadsetOn() || mStateManager + .getAudioManager().isMusicActive()))) { + widgetType = "media"; + } + + // get the widget + AppWidgetHostView hostView = mStateManager.getHMAppWidgetManager() + .getAppWidgetHostViewByType(widgetType); + + // add the required widget + if (hostView != null) { + ((RelativeLayout) defaultWidgetAreaVG).removeAllViews(); + + // if the widget host view already has a parent then we need to + // detach it + ViewGroup parent = (ViewGroup) hostView.getParent(); + if (parent != null) { + Log.d(LOG_TAG + daId + ".sWC", + "hostView had already been added to a group, detaching it."); + parent.removeView(hostView); + } + + // add the widget to the view + ((RelativeLayout) defaultWidgetAreaVG).addView(hostView); + + changeTimeDateDisplay(true); + defaultWidgetAreaVG.setVisibility(View.VISIBLE); + findViewById(R.id.default_text_fulltime_very_small).setVisibility( + View.VISIBLE); + } else { + defaultWidgetAreaVG.setVisibility(View.GONE); + findViewById(R.id.default_text_fulltime_very_small).setVisibility( + View.GONE); + changeTimeDateDisplay(); + } + } /** Called when the user touches the snooze button */ public void sendSnooze(View view) { - // Broadcast alarm snooze event - Intent alarmSnooze = new Intent(ALARM_SNOOZE_ACTION); - sendBroadcast(alarmSnooze); - //unset alarm firing flag - alarm_firing = false; - //refresh the display - refreshDisplay(); + Log.d(LOG_TAG + daId, "Alarm button: snooze alarm"); + Intent alarmSnooze = new Intent(this, CoreService.class); + alarmSnooze.putExtra(CoreApp.CS_EXTRA_TASK, + CoreApp.CS_TASK_SNOOZE_ALARM); + mStateManager.sendToCoreService(alarmSnooze); } /** Called when the user touches the dismiss button */ public void sendDismiss(View view) { - // Broadcast alarm dismiss event - Intent alarmDismiss = new Intent(ALARM_DISMISS_ACTION); - sendBroadcast(alarmDismiss); - //unset alarm firing flag - alarm_firing = false; - //refresh the display - refreshDisplay(); + Log.d(LOG_TAG + daId, "Alarm button: dismiss... I am wake"); + Intent alarmDismiss = new Intent(this, CoreService.class); + alarmDismiss.putExtra(CoreApp.CS_EXTRA_TASK, + CoreApp.CS_TASK_SNOOZE_ALARM); + mStateManager.sendToCoreService(alarmDismiss); } - + + /** Called when the user touches the hangup button */ public void sendHangUp(View view) { - Functions.Actions.hangup_call(); + Intent hangUpCallIntent = new Intent(this, CoreService.class); + hangUpCallIntent.putExtra(CoreApp.CS_EXTRA_TASK, + CoreApp.CS_TASK_HANGUP_CALL); + mStateManager.sendToCoreService(hangUpCallIntent); } - + + /** Called when the user touches the pickup button */ public void sendPickUp(View view) { - Functions.Actions.pickup_call(); + Intent pickUpCallIntent = new Intent(this, CoreService.class); + pickUpCallIntent.putExtra(CoreApp.CS_EXTRA_TASK, + CoreApp.CS_TASK_PICKUP_CALL); + mStateManager.sendToCoreService(pickUpCallIntent); } - //toggle the torch + /** Called when the user touches the torch button */ public void sendToggleTorch(View view) { - Functions.Actions.toggle_torch(this); - } - - //toggle the alternative torch - public void toggleTorch(View view) { - Functions.Actions.toggle_torch_alternative(this); - } - - //fire up the camera - public void camera_start(View view) { - if (Functions.flashIsOn) { - TorchActions.turnOffFlash(); - torchButton2.setImageResource(R.drawable.ic_appwidget_torch_off); + Intent torchIntent = new Intent(this, CoreService.class); + torchIntent.putExtra(CoreApp.CS_EXTRA_TASK, + CoreApp.CS_TASK_TORCH_TOGGLE); + mStateManager.sendToCoreService(torchIntent); + } + + // from + // http://stackoverflow.com/questions/3712112/search-contact-by-phone-number + private String getContactName(Context ctx, String number) { + + if (number.equals("")) { + return ""; + } + + Log.d(LOG_TAG + daId + ".contact", "looking up " + number + "..."); + + Uri uri = Uri.withAppendedPath( + ContactsContract.PhoneLookup.CONTENT_FILTER_URI, + Uri.encode(number)); + String name = number; + + ContentResolver contentResolver = ctx.getContentResolver(); + Cursor contactLookup = contentResolver.query(uri, new String[] { + BaseColumns._ID, ContactsContract.PhoneLookup.DISPLAY_NAME }, + null, null, null); + + try { + if (contactLookup != null && contactLookup.getCount() > 0) { + contactLookup.moveToNext(); + name = contactLookup.getString(contactLookup + .getColumnIndex(ContactsContract.Data.DISPLAY_NAME)); + // String contactId = + // contactLookup.getString(contactLookup.getColumnIndex(BaseColumns._ID)); + } + } finally { + if (contactLookup != null) { + contactLookup.close(); + } } - Functions.Actions.start_camera(this); + + Log.d(LOG_TAG + daId + ".contact", "...result is " + name); + return name; } - - public void camera_capture(View view) { - Log.d("hm-cam", "say cheese"); - ((CameraPreview)findViewById(R.id.default_camera)).capture(); + + // fire up the camera + public void startCamera(View view) { + startCamera(); } - - public void camera_back(View view) { - Functions.Actions.end_camera(this); + + public void startCamera() { + Log.d(LOG_TAG, "starting camera"); + mStateManager.setCameraUp(true); + mStateManager.setBlackScreenTime(0); + getWindow().addFlags( + WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON + | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + + if (mStateManager.getTorchOn() + && mStateManager.getPreference().getBoolean( + "pref_flash_controls_alternative", false)) { + mStateManager.turnOffFlash(); + torchButton.setImageResource(R.drawable.ic_appwidget_torch_off); + } + findViewById(R.id.default_camera).setVisibility(View.VISIBLE); + displayCamera(); + Log.d(LOG_TAG, "started camera"); } - + + public void captureCamera(View view) { + Log.d(LOG_TAG, "camera say cheese"); + ((CameraPreview) findViewById(R.id.default_camera)).capture(); + } + + public void stopCamera(View view) { + stopCamera(); + Log.d(LOG_TAG, "closed camera"); + } + + public void stopCamera() { + mStateManager.setCameraUp(false); + refreshDisplay(); + findViewById(R.id.default_camera).setVisibility(View.INVISIBLE); + Intent mIntent = new Intent(this, CoreService.class); + mIntent.putExtra(CoreApp.CS_EXTRA_TASK, + CoreApp.CS_TASK_AUTO_BLACKSCREEN); + mStateManager.sendToCoreService(mIntent); + } + + private void setRealFullscreen() { + if (mStateManager.getPreference().getBoolean("pref_realfullscreen", + false)) { + // Remove notification bar + allLayoutParams |= WindowManager.LayoutParams.FLAG_FULLSCREEN; + + // Remove navigation bar + View decorView = getWindow().getDecorView(); + decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar + | View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); + } + } + + /* + * private void reload() { set_real_fullscreen(); choose_layout(); + * torchButton = (ImageButton) findViewById(R.id.torchbutton); cameraButton + * = (ImageButton) findViewById(R.id.camerabutton); choose_call_input(); + * choose_alarm_input(); choose_torch_input(); + * + * changeColor(); visibilityTorchButton(); visibilityCameraButton(); + * setWidgetContent(); + * + * findViewById(R.id.default_main).setLongClickable(true); + * findViewById(R.id.default_main).setOnTouchListener( new + * SwipeTouchListener(this, + * SwipeTouchListener.ActionMode.MODE_NOTHINGTRUE)); + * findViewById(R.id.default_undercover).setLongClickable(true); + * findViewById(R.id.default_undercover).setOnTouchListener( new + * SwipeTouchListener(this, + * SwipeTouchListener.ActionMode.MODE_NOTHINGTRUE)); } + */ + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + daId = CoreStateManager.createID(); + Log.d(LOG_TAG + daId + ".onCreate", "creating"); - //pass a reference back to the Functions class so it can finish us when it wants to - //FIXME Presumably there is a better way to do this - Functions.defaultActivity = this; + mStateManager = ((CoreApp) getApplicationContext()).getStateManager(); - Log.d("DA.onCreate", "onCreate of DefaultView."); + mStateManager.setDefaultActivityStarting(true); - //set default view - - Functions.Actions.choose_layout(this); + // pass a reference back to the state manager + if (!mStateManager.setDefaultActivity(this)) { + Log.w(LOG_TAG + daId, "Warning already default activity set!!!!"); + finish(); + return; + } - //get the audio manager - audioManager = (AudioManager) getApplicationContext().getSystemService(Context.AUDIO_SERVICE); + mStateManager.acquireCPUDA(); - //add screen on and alarm fired intent receiver - getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_SCREEN_ON); - filter.addAction(ALARM_ALERT_ACTION); - filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED); - filter.addAction("org.durka.hallmonitor.debug"); - filter.addAction(ALARM_DONE_ACTION); - registerReceiver(receiver, filter); - - //get the views we need - torchButton = (ImageButton) findViewById(R.id.torchbutton); - torchButton2 = (ImageButton) findViewById(R.id.torchbutton2); - cameraButton = (ImageButton) findViewById(R.id.camerabutton); + mStateManager.closeConfigurationActivity(); - //home key hack - homeKeyLocker = new HomeKeyLocker(); - } + // Remove title bar + requestWindowFeature(Window.FEATURE_NO_TITLE); - @Override - public void onWindowFocusChanged(boolean hasFocus) { - super.onWindowFocusChanged(hasFocus); + // Display in fullscreen + setRealFullscreen(); + + if (mStateManager.getHardwareAccelerated()) { + allLayoutParams |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; - if(hasFocus) { - Functions.Actions.enableCoverTouch(getBaseContext(), true); - refreshDisplay(); } + // Keep screen on during display + allLayoutParams |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON + | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON + // Display before lock screen + | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED + // Enable multitouch started outside view + | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH; + + getWindow().addFlags(allLayoutParams); + setMainLayout(); + + // get the views we need + torchButton = (ImageButton) findViewById(R.id.torchbutton); + cameraButton = (ImageButton) findViewById(R.id.camerabutton); + defaultWidgetAreaVG = (ViewGroup) findViewById(R.id.default_widget_area); + + // home key hack + homeKeyLocker = new HomeKeyLocker(); + + setCallInput(); + setAlarmInput(); + setNormalInput(); + + changeColor(); + visibilityTorchButton(); + visibilityCameraButton(); + setWidgetContent(); + + findViewById(R.id.default_main).setLongClickable(true); + findViewById(R.id.default_main).setOnTouchListener( + new SwipeTouchListener(this, + SwipeTouchListener.ActionMode.MODE_NOTHINGTRUE)); + findViewById(R.id.default_undercover).setLongClickable(true); + findViewById(R.id.default_undercover).setOnTouchListener( + new SwipeTouchListener(this, + SwipeTouchListener.ActionMode.MODE_NOTHINGTRUE)); + mMessageReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (action.equals(CoreApp.DA_ACTION_TORCH_STATE_CHANGED)) { + if (intent.getBooleanExtra(CoreApp.DA_EXTRA_STATE, false)) { + runOnUiThread(new Runnable() { + @Override + public void run() { + torchButton + .setImageResource(R.drawable.ic_appwidget_torch_on); + } + }); + } else { + runOnUiThread(new Runnable() { + @Override + public void run() { + torchButton + .setImageResource(R.drawable.ic_appwidget_torch_off); + } + }); + } + + } else if (action.equals(CoreApp.DA_ACTION_WIDGET_REFRESH)) { + setWidgetContent(); + + } else if (action.equals(CoreApp.DA_ACTION_BATTERY_REFRESH)) { + setBatteryIcon(); + + } else if (action + .equals(CoreApp.DA_ACTION_NOTIFICATION_REFRESH)) { + refreshNotifications(); + + } else if (action.equals(CoreApp.DA_ACTION_START_CAMERA)) { + startCamera(); + + } else if (action.equals(CoreApp.DA_ACTION_STATE_CHANGED)) { + switch (intent.getIntExtra(CoreApp.DA_EXTRA_STATE, 0)) { + case CoreApp.DA_EXTRA_STATE_NORMAL: + displayNormal(); + break; + case CoreApp.DA_EXTRA_STATE_ALARM: + displayAlarm(); + break; + case CoreApp.DA_EXTRA_STATE_PHONE: + displayPhone(); + break; + case CoreApp.DA_EXTRA_STATE_CAMERA: + displayCamera(); + break; + } + + } else if (action.equals(CoreApp.DA_ACTION_SEND_TO_BACKGROUND)) { + Log.d(LOG_TAG + daId, "Send to background"); + moveTaskToBack(true); + + } else if (action.equals(CoreApp.DA_ACTION_FREE_SCREEN)) { + Log.d(LOG_TAG + daId, "Call to finish"); + getWindow() + .clearFlags( + WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON + | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + + } else if (action.equals(CoreApp.DA_ACTION_FINISH)) { + if (mStateManager.getDefaultActivityStarting()) { + Log.w(LOG_TAG + daId, "Starting, could not finish"); + } else { + Log.d(LOG_TAG + daId, "Call to finish"); + finish(); + } + } + } + }; + + IntentFilter mIntentFilter = new IntentFilter(); + mIntentFilter.addAction(CoreApp.DA_ACTION_BATTERY_REFRESH); + mIntentFilter.addAction(CoreApp.DA_ACTION_FINISH); + mIntentFilter.addAction(CoreApp.DA_ACTION_FREE_SCREEN); + mIntentFilter.addAction(CoreApp.DA_ACTION_NOTIFICATION_REFRESH); + mIntentFilter.addAction(CoreApp.DA_ACTION_SEND_TO_BACKGROUND); + mIntentFilter.addAction(CoreApp.DA_ACTION_START_CAMERA); + mIntentFilter.addAction(CoreApp.DA_ACTION_STATE_CHANGED); + mIntentFilter.addAction(CoreApp.DA_ACTION_TORCH_STATE_CHANGED); + mIntentFilter.addAction(CoreApp.DA_ACTION_WIDGET_REFRESH); + LocalBroadcastManager.getInstance(this).registerReceiver( + mMessageReceiver, mIntentFilter); } @Override - protected void onStart() { - super.onStart(); - Log.d("DA-oS", "starting"); - on_screen = true; + public void onWindowFocusChanged(boolean hasWindowFocus) { + super.onWindowFocusChanged(hasWindowFocus); - if (NotificationService.that != null) { - // notification listener service is running, show the current notifications - // TODO move this to Functions.java - Functions.Actions.setup_notifications(); + if (hasWindowFocus) { + mStateManager.acquireCPUDA(); + Log.d(LOG_TAG + daId + ".onWFC", "Get focus."); + } else { + mStateManager.releaseCPUDA(); + Log.d(LOG_TAG + daId + ".onWFC", "No focus."); } + } - @Override - protected void onPause() { - super.onPause(); + protected void onStart() { + mStateManager.acquireCPUDA(); + Log.d(LOG_TAG + daId + ".onStart", "starting"); + mStateManager.setDefaultActivityStarting(true); - homeKeyLocker.unlock(); + super.onStart(); } - + @Override protected void onResume() { - super.onResume(); + mStateManager.acquireCPUDA(); + Log.d(LOG_TAG + daId + ".onResume", "resuming"); + mStateManager.setDefaultActivityStarting(true); - if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean("pref_disable_home", true)) { - homeKeyLocker.lock(this); - } - - // load debug setting - mDebug = PreferenceManager.getDefaultSharedPreferences(getBaseContext()).getBoolean("pref_dev_opts_debug", false); + // Keep screen on during display + getWindow().addFlags( + WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON + | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - Log.d("DA.onResume", "On resume called."); + if (NotificationService.that != null) { + // notification listener service is running, show the current + // notifications + setupNotifications(); + refreshNotifications(); + } + + refreshDisplay(); + + /* + * // check preview (extras are configured in xml) if + * (getIntent().getExtras() != null && + * !getIntent().getExtras().getString("preview", "").equals("")) { + * String preview = getIntent().getExtras().getString("preview"); + * + * if (preview.equals("phoneWidget")) { new AlertDialog.Builder(this) + * .setMessage( + * "search AlertDialog in DefaultActivity to place your code for preview of '" + * + preview + "' there!") .setPositiveButton(android.R.string.yes, new + * DialogInterface.OnClickListener() { public void + * onClick(DialogInterface dialog, int which) { finish(); } }) .show(); + * } } + */ + if (mStateManager.getPreference().getBoolean("pref_disable_home", true)) { + homeKeyLocker.lock(this); + } + + Intent touchCoverIntent = new Intent(this, CoreService.class); + touchCoverIntent.putExtra(CoreApp.CS_EXTRA_TASK, + CoreApp.CS_TASK_CHANGE_TOUCHCOVER); + touchCoverIntent.putExtra(CoreApp.CS_EXTRA_STATE, true); + mStateManager.sendToCoreService(touchCoverIntent); + + mainView.requestLayout(); + mainView.requestFocus(); + + super.onResume(); - refreshDisplay(); // TODO is this necessary to do here?` + mStateManager.releaseCPUDA(); + } - /* - // check preview (extras are configured in xml) - if (getIntent().getExtras() != null && !getIntent().getExtras().getString("preview", "").equals("")) { - String preview = getIntent().getExtras().getString("preview"); + @Override + protected void onPause() { + Log.d(LOG_TAG + daId + ".onPause", "pausing"); - if (preview.equals("phoneWidget")) { - new AlertDialog.Builder(this) - .setMessage("search AlertDialog in DefaultActivity to place your code for preview of '" + preview + "' there!") - .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - finish(); - } - }) - .show(); - } - } - */ + Intent mIntent = new Intent(this, CoreService.class); + mIntent.putExtra(CoreApp.CS_EXTRA_TASK, + CoreApp.CS_TASK_CHANGE_TOUCHCOVER); + mStateManager.sendToCoreService(mIntent); + homeKeyLocker.unlock(); + + mStateManager.releaseCPUDA(); + super.onPause(); } @Override protected void onStop() { - super.onStop(); - Log.d("DA-oS", "stopping"); - Functions.Actions.dismiss_keyguard(this); - if (Functions.Actions.timerTask != null) { - Functions.Actions.timerTask.cancel(); + Log.d(LOG_TAG + daId + ".onStop", "stopping"); + + if (mStateManager.getPreference().getBoolean("pref_keyguard", true)) { + getWindow().addFlags( + WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD); } - if (Functions.flashIsOn) { - TorchActions.turnOffFlash(); + if (mStateManager.getTorchOn() + && mStateManager.getPreference().getBoolean( + "pref_flash_controls_alternative", false)) { + Intent torchIntent = new Intent(this, CoreService.class); + torchIntent.putExtra(CoreApp.CS_EXTRA_TASK, + CoreApp.CS_TASK_TORCH_TOGGLE); + mStateManager.sendToCoreService(torchIntent); } - if (camera_up) { - Functions.Actions.end_camera(this, false); + if (mStateManager.getCameraUp()) { + mStateManager.setCameraUp(false); } - on_screen = false; + super.onStop(); } @Override protected void onDestroy() { + Log.d(LOG_TAG + daId + ".onDestroy", "detroying"); + mStateManager.setDefaultActivityStarting(false); + + LocalBroadcastManager.getInstance(this).unregisterReceiver( + mMessageReceiver); + mStateManager.releaseCPUDA(); + mStateManager.setDefaultActivity(null); super.onDestroy(); - //tidy up our receiver when we are destroyed - unregisterReceiver(receiver); } - - public static boolean isDebug() { - return mDebug; - } - } diff --git a/src/org/durka/hallmonitor/Functions.java b/src/org/durka/hallmonitor/Functions.java deleted file mode 100644 index 4ec0d4b..0000000 --- a/src/org/durka/hallmonitor/Functions.java +++ /dev/null @@ -1,967 +0,0 @@ -/* Copyright 2013 Alex Burka - - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.durka.hallmonitor; - -import java.io.File; -import java.io.FileNotFoundException; -import java.util.Scanner; -import java.util.Timer; -import java.util.TimerTask; - -import android.app.Activity; -import android.app.ActivityManager; -import android.app.ActivityManager.RunningServiceInfo; -import android.app.Notification; -import android.app.NotificationManager; -import android.app.admin.DevicePolicyManager; -import android.appwidget.AppWidgetManager; -import android.content.ComponentName; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.os.Build; -import android.database.Cursor; -import android.hardware.Camera; -import android.hardware.Camera.Parameters; -import android.net.Uri; -import android.os.AsyncTask; -import android.os.Handler; -import android.os.PowerManager; -import android.preference.PreferenceManager; -import android.provider.BaseColumns; -import android.provider.ContactsContract; -import android.service.notification.StatusBarNotification; -import android.os.SystemClock; -import android.util.Log; -import android.view.View; -import android.view.WindowManager; -import android.widget.GridView; -import android.widget.TextView; -import android.widget.Toast; -import eu.chainfire.libsuperuser.Shell; - -/** - * Container Class for various inner Classes which service the capabilities of the HallMonitor app. - */ -public class Functions { - - // callback identifiers for startActivityForResult, used by the preference screen - public static final int DEVICE_ADMIN_WAITING = 42; - public static final int REQUEST_PICK_APPWIDGET = 9; - public static final int REQUEST_CONFIGURE_APPWIDGET = 5; - public static final int NOTIFICATION_LISTENER_ON = 0xDEAD; - public static final int NOTIFICATION_LISTENER_OFF = 0xBEEF; - - //this action will let us toggle the flashlight - public static final String TOGGLE_FLASHLIGHT = "net.cactii.flash2.TOGGLE_FLASHLIGHT"; - - private static final String DEV_SERRANO_LTE_CM10 = "serranolte"; // GT-I9195 CM10.x - private static final String DEV_SERRANO_LTE_CM11 = "serranoltexx"; // GT-I9195 CM11.x - private static final String DEV_SERRANO_DS_CM10 = "serranods"; // GT-I9192 CM10.x - private static final String DEV_SERRANO_DS_CM11 = "serranodsxx"; // GT-I9192 CM11.x - - //All we need for alternative torch - private static Camera camera; - public static boolean flashIsOn = false; - public static boolean deviceHasFlash; - - //Class that handles interaction with 3rd party App Widgets - public static final HMAppWidgetManager hmAppWidgetManager = new HMAppWidgetManager(); - - public static DefaultActivity defaultActivity; - public static Configuration configurationActivity; - - private static boolean notification_settings_ongoing = false; - public static boolean widget_settings_ongoing = false; - - /** - * Provides methods for performing actions. (e.g. what to do when the cover is opened and closed etc.) - */ - public static class Actions { - - //used for the timer to turn off the screen on a delay - public static Timer timer = new Timer(); - public static TimerTask timerTask; - - - /** - * Called whenever the cover_closed event is called. Also called from DefaultActivity when the - * screen turns on whilst the cover is closed. - * Switches to the default activity screen and if we are running root enabled boosts the screen sensitivity. - * After pref_delay milliseconds locks the screen. - * @param ctx Application context. - */ - public static void close_cover(Context ctx) { - - Log.d("F.Act.close_cover", "Close cover event receieved."); - - //save the cover state - Events.set_cover(true); - - enableCoverTouch(ctx, true); - - // step 1: bring up the default activity window - //we are using the show when locked flag as we'll re-use this method to show the screen on power button press - if (!DefaultActivity.on_screen) { - ctx.startActivity(new Intent(ctx, DefaultActivity.class) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_NO_ANIMATION - | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED)); - } - - //need this to let us lock the phone - final DevicePolicyManager dpm = (DevicePolicyManager) ctx.getSystemService(Context.DEVICE_POLICY_SERVICE); - - ComponentName me = new ComponentName(ctx, AdminReceiver.class); - if (!dpm.isAdminActive(me)) { - // if we're not an admin, we can't do anything - Log.d("F.Act.close_cover", "We are not an admin so cannot do anything."); - return; - } - - //step 2: wait for the delay period and turn the screen off - setCloseTimer(ctx); - - } - - - public static void setCloseTimer(Context ctx) { - if(Is.SystemApp(ctx)) { - setSleepTimer(ctx, PreferenceManager.getDefaultSharedPreferences(ctx).getInt("pref_delay", 10000)); - } - else - { - setLockTimer(ctx, PreferenceManager.getDefaultSharedPreferences(ctx).getInt("pref_delay", 10000)); - } - } - - public static void setLockTimer(Context ctx, int delay) { - timer.cancel(); - - timer = new Timer(); - - //need this to let us lock the phone - final DevicePolicyManager dpm = (DevicePolicyManager) ctx.getSystemService(Context.DEVICE_POLICY_SERVICE); - - //using the handler is causing a problem, seems to lock up the app, hence replaced with a Timer - timer.schedule(timerTask = new TimerTask() { - //handler.postDelayed(new Runnable() { - @Override - public void run() { - Log.d("F.Act.close_cover", "Locking screen now."); - dpm.lockNow(); - //FIXME Would it be better to turn the screen off rather than actually locking - //presumably then it will auto lock as per phone configuration - //I can't work out how to do it though! - } - }, delay); - - Log.d("F.Act.setLockTimer", "Delay set to: " + delay); - } - - public static void setSleepTimer(Context ctx, int delay) { - timer.cancel(); - - timer = new Timer(); - - final PowerManager pm = (PowerManager) ctx.getSystemService(Context.POWER_SERVICE); - - timer.schedule(timerTask = new TimerTask() { - @Override - public void run() { - if (pm.isScreenOn()){ - Log.d("F.Act.close_cover", "Go to sleep now."); - pm.goToSleep(SystemClock.uptimeMillis()); - } - else{ - Log.d("F.Act.close_cover", "Screen already off."); - } - } - }, delay); - - Log.d("F.Act.setSleepTimer", "Delay set to: " + delay); - } - - public static void enableCoverTouch(Context ctx, Boolean value) { - //if we are running in root enabled mode then lets up the sensitivity on the view screen - //so we can use the screen through the window - if (PreferenceManager.getDefaultSharedPreferences(ctx).getBoolean("pref_runasroot", false)) { - if(value) { - Log.d("F.Act.enableCoverTouch", "We're root enabled so lets boost the sensitivity..."); - if (Build.DEVICE.equals(DEV_SERRANO_LTE_CM10) || Build.DEVICE.equals(DEV_SERRANO_LTE_CM11) || Build.DEVICE.equals(DEV_SERRANO_DS_CM10) || Build.DEVICE.equals(DEV_SERRANO_DS_CM11)) { - AsyncSuRunMulti localSuRunMulti = new AsyncSuRunMulti(); - localSuRunMulti.execute(new String[]{"echo module_on_master > /sys/class/sec/tsp/cmd && cat /sys/class/sec/tsp/cmd_result", "echo clear_cover_mode,3 > /sys/class/sec/tsp/cmd && cat /sys/class/sec/tsp/cmd_result"}); - } - else { // others devices - AsyncSuRun localSuRun = new AsyncSuRun(); - localSuRun.execute("echo clear_cover_mode,1 > /sys/class/sec/tsp/cmd"); - } - Log.d("F.Act.enableCoverTouch", "...Sensitivity boosted, hold onto your hats!"); - } - else { - Log.d("F.Act.enableCoverTouch", "We're root enabled so lets revert the sensitivity..."); - AsyncSuRunMulti localSuRunMulti = new AsyncSuRunMulti(); - localSuRunMulti.execute(new String[]{"cd /sys/class/sec/tsp", "echo clear_cover_mode,0 > cmd && cat /sys/class/sec/tsp/cmd_result"}); - Log.d("F.Act.enableCoverTouch", "...Sensitivity reverted, sanity is restored!"); - } - } - } - - /** - * Called from within the ViewCoverHallService.run method - * or called from within the Functions.Event.Proximity method. - * If we are running root enabled reverts the screen sensitivity. - * Wakes the screen up. - * @param ctx Application context. - */ - public static void open_cover(Context ctx) { - - Log.d("F.Act.open_cover", "Open cover event receieved."); - - /* - //we don't want the configuration screen displaying when we wake back up - if (configurationActivity != null) configurationActivity.moveTaskToBack(true); - //we also don't want to see the default activity - if (defaultActivity != null) { - Log.d("DA.onReceive", "Current task: " + ((ActivityManager)defaultActivity.getSystemService(Context.ACTIVITY_SERVICE)).getRunningTasks(1).get(0).topActivity.getPackageName()); - defaultActivity.moveTaskToBack(true); - } - */ - if (configurationActivity != null) configurationActivity.finish(); - if (defaultActivity != null) defaultActivity.finish(); - - // step 1: if we were going to turn the screen off, cancel that - if (timerTask != null) timerTask.cancel(); - - enableCoverTouch(ctx, false); - - // step 2: wake the screen - Util.rise_and_shine(ctx); - - //save the cover state - Events.set_cover(false); - } - - - /** - * Starts the HallMonitor service. Service state is dependent on admin permissions. - * This requests admin permissions. The onActionReceiver will pick that up - * and do the necessary to start the service. - * @param act Activity context. - */ - public static void start_service(Activity act) { - Log.d("F.Act.start_service", "Start service called."); - // Become device admin - DevicePolicyManager dpm = (DevicePolicyManager) act.getSystemService(Context.DEVICE_POLICY_SERVICE); - ComponentName me = new ComponentName(act, AdminReceiver.class); - if (!dpm.isAdminActive(me)) { - Log.d("F.Act.start_service", "launching dpm overlay"); - Intent coup = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN); - coup.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, me); - coup.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION, act.getString(R.string.admin_excuse)); - act.startActivityForResult(coup, DEVICE_ADMIN_WAITING); - } else { - // we were already admin, just start the service - if(PreferenceManager.getDefaultSharedPreferences(act).getBoolean("pref_realhall", false)) { - act.startService(new Intent(act, ViewCoverHallService.class)); - } - else { - act.startService(new Intent(act, ViewCoverProximityService.class)); - } - } - } - - /** - * Stops the HallMonitor service. - * @param ctx Application context. - */ - public static void stop_service(Context ctx) { - stop_service(ctx, false); - } - public static void stop_service(Context ctx, boolean override_keep_admin) { - - Log.d("F.Act.stop_service", "Stop service called."); - - ctx.stopService(new Intent(ctx, ViewCoverHallService.class)); - ctx.stopService(new Intent(ctx, ViewCoverProximityService.class)); - ctx.stopService(new Intent(ctx, NotificationService.class)); - - // Relinquish device admin (unless asked not to) - if (!override_keep_admin && !PreferenceManager.getDefaultSharedPreferences(ctx).getBoolean("pref_keep_admin", false)) { - DevicePolicyManager dpm = (DevicePolicyManager) ctx.getSystemService(Context.DEVICE_POLICY_SERVICE); - ComponentName me = new ComponentName(ctx, AdminReceiver.class); - if (dpm.isAdminActive(me)) dpm.removeActiveAdmin(me); - } - } - - public static void do_notifications(Activity act, boolean enable) { - - if (enable && !notification_settings_ongoing && !Is.service_running(act, NotificationService.class)) { - notification_settings_ongoing = true; - Toast.makeText(act, act.getString(R.string.notif_please_check), Toast.LENGTH_SHORT).show(); - act.startActivityForResult(new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"), NOTIFICATION_LISTENER_ON); - } else if (!enable && !notification_settings_ongoing && Is.service_running(act, NotificationService.class)) { - notification_settings_ongoing = true; - Toast.makeText(act, act.getString(R.string.notif_please_uncheck), Toast.LENGTH_SHORT).show(); - act.startActivityForResult(new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"), NOTIFICATION_LISTENER_OFF); - } - - } - - /** - * Hand off to the HMAppWidgetManager to deal with registering new app widget. - * @param act The Activity to use as the context for these actions - * @param widgetType The type of widget (e.g. 'default', 'media', 'notification' etc.) - */ - public static void register_widget(Activity act, String widgetType) { - - Log.d("F.Act.register_widget", "Register widget called for type: " + widgetType); - //hand off to the HM App Widget Manager for processing - if (widget_settings_ongoing) { - Log.d("F.Act.register_widget", "skipping, already inflight"); - } else { - hmAppWidgetManager.register_widget(act, widgetType); - } - } - - /** - * Hand off to the HMAppWidgetManager to deal with unregistering existing app widget. - * @param act The Activity to use as the context for these actions - * @param widgetType The type of widget (e.g. 'default', 'media', 'notification' etc.) - */ - public static void unregister_widget(Activity act, String widgetType) { - - Log.d("F.Act.unregister_widget", "unregister widget called for type: " + widgetType); - //hand off to the HM App Widget Manager for processing - hmAppWidgetManager.unregister_widget(act, widgetType); - } - - - - public static void hangup_call() { - Log.d("phone", "hanging up! goodbye"); - //if(configurationActivity != null && configurationActivity.isSystemApp) { - //} - //else { - AsyncSuRun localSuRun = new AsyncSuRun(); - localSuRun.execute("input keyevent 6"); - //} - DefaultActivity.phone_ringing = false; - defaultActivity.refreshDisplay(); - setCloseTimer(defaultActivity); - } - - public static void pickup_call() { - Log.d("phone", "picking up! hello"); - //if(configurationActivity != null && configurationActivity.isSystemApp) { - //} - //else { - AsyncSuRun localSuRun = new AsyncSuRun(); - localSuRun.execute("input keyevent 5"); - setCloseTimer(defaultActivity); - //} - //DefaultActivity.phone_ringing = false; - //defaultActivity.refreshDisplay(); - } - - public static void toggle_torch(DefaultActivity da) { - Intent intent = new Intent(TOGGLE_FLASHLIGHT); - intent.putExtra("strobe", false); - intent.putExtra("period", 100); - intent.putExtra("bright", false); - da.sendBroadcast(intent); - Is.torchIsOn = !Is.torchIsOn; - if (Is.torchIsOn) { - da.torchButton.setImageResource(R.drawable.ic_appwidget_torch_on); - if (timerTask != null) timerTask.cancel(); - } else { - da.torchButton.setImageResource(R.drawable.ic_appwidget_torch_off); - close_cover(da); - } - } - - public static void toggle_torch_alternative(DefaultActivity da) { - if (!flashIsOn) { - TorchActions.turnOnFlash(); - da.torchButton2.setImageResource(R.drawable.ic_appwidget_torch_on); - if (Actions.timerTask != null) Actions.timerTask.cancel(); - } else { - TorchActions.turnOffFlash(); - da.torchButton2.setImageResource(R.drawable.ic_appwidget_torch_off); - close_cover(da); - } - } - - public static void start_camera(DefaultActivity da) { - if (timerTask != null) timerTask.cancel(); - DefaultActivity.camera_up = true; - da.refreshDisplay(); - da.findViewById(R.id.default_camera).setVisibility(View.VISIBLE); - } - - public static void end_camera(DefaultActivity da) { end_camera(da, true); } - - public static void end_camera(DefaultActivity da, boolean should_close) { - da.findViewById(R.id.default_camera).setVisibility(View.INVISIBLE); - DefaultActivity.camera_up = false; - da.refreshDisplay(); - if (should_close) close_cover(da); - } - - public static void setup_notifications() { - StatusBarNotification[] notifs = NotificationService.that.getActiveNotifications(); - Log.d("DA-oC", Integer.toString(notifs.length) + " notifications"); - GridView grid = (GridView)defaultActivity.findViewById(R.id.default_icon_container); - grid.setNumColumns(notifs.length); - grid.setAdapter(new NotificationAdapter(defaultActivity, notifs)); - } - - public static void refresh_notifications() { - final GridView grid = (GridView)defaultActivity.findViewById(R.id.default_icon_container); - final NotificationAdapter adapter = (NotificationAdapter)grid.getAdapter(); - final StatusBarNotification[] notifs = NotificationService.that.getActiveNotifications(); - adapter.update(notifs); - defaultActivity.runOnUiThread(new Runnable() { - - @Override - public void run() { - - grid.setNumColumns(notifs.length); - adapter.notifyDataSetChanged(); - } - - }); - } - - - public static void debug_notification(Context ctx, boolean showhide) { - if (showhide) { - Notification.Builder mBuilder = - new Notification.Builder(ctx) - .setSmallIcon(R.drawable.ic_launcher) - .setContentTitle("Hall Monitor") - .setContentText("Debugging is fun!"); - - NotificationManager mNotificationManager = - (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE); - mNotificationManager.notify(42, mBuilder.build()); - } else { - NotificationManager mNotificationManager = - (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE); - mNotificationManager.cancel(42); - } - } - - public static void dismiss_keyguard (Context ctx) { - if (PreferenceManager.getDefaultSharedPreferences(ctx).getBoolean("pref_keyguard", true)) { - defaultActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD); - } - } - - public static void choose_layout (Context ctx) { - if (PreferenceManager.getDefaultSharedPreferences(ctx).getBoolean("pref_layout", true)) { - ((DefaultActivity) ctx).setContentView(R.layout.activity_alternative); - if (PreferenceManager.getDefaultSharedPreferences(ctx).getBoolean("pref_do_notifications", true)) { - defaultActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); - defaultActivity.findViewById(R.id.default_battery_percent).setVisibility(View.INVISIBLE); - defaultActivity.findViewById(R.id.default_battery_picture_horizontal).setVisibility(View.INVISIBLE); - - } - } else { - ((DefaultActivity) ctx).setContentView(R.layout.activity_default); - } - } - - public static void choose_call_layout (Context ctx) { - if (PreferenceManager.getDefaultSharedPreferences(ctx).getBoolean("pref_incoming_call_layout", false)) { - defaultActivity.findViewById(R.id.hangup_button).setOnTouchListener(new SwipeTouchListener(ctx)); - defaultActivity.findViewById(R.id.pickup_button).setOnTouchListener(new SwipeTouchListener(ctx)); - } else { - defaultActivity.findViewById(R.id.pickup_button).setOnTouchListener(new CallTouchListener()); - defaultActivity.findViewById(R.id.hangup_button).setOnTouchListener(new CallTouchListener()); - defaultActivity.findViewById(R.id.callchoice).setOnDragListener(new CallDragListener()); - } - } - - private static class AsyncSuRun extends AsyncTask { - @Override - protected String doInBackground(String... params) { - Shell.SU.run(params[0]); - return "Executed"; - } - } - - private static class AsyncSuRunMulti extends AsyncTask { - @Override - protected String doInBackground(String[]... params) { - Shell.SU.run(params[0]); - return "Executed"; - } - } - } - - - /** - * Provides event handling. - */ - public static class Events { - - //is the cover closed - private static boolean cover_closed; - - /** - * Invoked from the BootReceiver, allows for start on boot, as is registered in the manifest as listening for: - * android.intent.action.BOOT_COMPLETED and - * android:name="android.intent.action.QUICKBOOT_POWERON" - * Starts the ViewCoverService which handles detection of the cover state. - * @param ctx Application context - */ - public static void boot(Context ctx) { - - Log.d("F.Evt.boot", "Boot called."); - - if (PreferenceManager.getDefaultSharedPreferences(ctx).getBoolean("pref_enabled", false)) { - if(PreferenceManager.getDefaultSharedPreferences(ctx).getBoolean("pref_realhall", false)) { - Intent startServiceIntent = new Intent(ctx, ViewCoverHallService.class); - ctx.startService(startServiceIntent); - } - else { - Intent startServiceIntent = new Intent(ctx, ViewCoverProximityService.class); - ctx.startService(startServiceIntent); - } - } - - } - - - /** - * The Configuration activity acts as the main activity for the app. Any events received into - * its onActivityReceived method are passed on to be handled here. - * @param ctx Application context. - * @param request Request Activity ID. - * @param result Result Activity ID. - * @param data Intent that holds the data received. - */ - public static void activity_result(Context ctx, int request, int result, Intent data) { - Log.d("F.Evt.activity_result", "Activity result received: request=" + Integer.toString(request) + ", result=" + Integer.toString(result)); - switch (request) { - //call back for admin access request - case DEVICE_ADMIN_WAITING: - if (result == Activity.RESULT_OK) { - // we asked to be an admin and the user clicked Activate - // (the intent receiver takes care of showing a toast) - // go ahead and start the service - if(PreferenceManager.getDefaultSharedPreferences(ctx).getBoolean("pref_realhall", false)) { - ctx.startService(new Intent(ctx, ViewCoverHallService.class)); - } - else { - ctx.startService(new Intent(ctx, ViewCoverProximityService.class)); - } - } else { - // we asked to be an admin and the user clicked Cancel (why?) - // complain, and un-check pref_enabled - Toast.makeText(ctx, ctx.getString(R.string.admin_refused), Toast.LENGTH_SHORT).show(); - Log.d("F.Evt.activity_result", "pref_enabled = " + Boolean.toString(PreferenceManager.getDefaultSharedPreferences(ctx).getBoolean("pref_enabled", true))); - PreferenceManager.getDefaultSharedPreferences(ctx) - .edit() - .putBoolean("pref_enabled", false) - .commit(); - Log.d("F.Evt.activity_result", "pref_enabled = " + Boolean.toString(PreferenceManager.getDefaultSharedPreferences(ctx).getBoolean("pref_enabled", true))); - - } - break; - //call back for appwidget pick - case REQUEST_PICK_APPWIDGET: - //widget picked - widget_settings_ongoing = false; - if (result == Activity.RESULT_OK) { - //widget chosen so launch configurator - hmAppWidgetManager.configureWidget(data, ctx); - } else { - //choose dialog cancelled so clean up - int appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1); - if (appWidgetId != -1) { - hmAppWidgetManager.deleteAppWidgetId(appWidgetId); - PreferenceManager.getDefaultSharedPreferences(ctx) - .edit() - .putBoolean("pref_" + hmAppWidgetManager.currentWidgetType + "_widget", false) // FIXME this is a huge hack - .commit(); - } - - } - break; - //call back for appwidget configure - case REQUEST_CONFIGURE_APPWIDGET: - widget_settings_ongoing = false; - //widget configured - if (result == Activity.RESULT_OK) { - //widget configured successfully so create it - hmAppWidgetManager.createWidget(data, ctx); - } else { - //configure dialog cancelled so clean up - if (data != null) { - int appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1); - if (appWidgetId != -1) { - hmAppWidgetManager.deleteAppWidgetId(appWidgetId); - PreferenceManager.getDefaultSharedPreferences(ctx) - .edit() - .putBoolean("pref_" + hmAppWidgetManager.currentWidgetType + "_widget", false) // FIXME this is a huge hack - .commit(); - } - } - - } - break; - - - case NOTIFICATION_LISTENER_ON: - Log.d("F-oAR", "return from checking the box"); - notification_settings_ongoing = false; - if (!Functions.Is.service_running(ctx, NotificationService.class)) { - Toast.makeText(ctx, ctx.getString(R.string.notif_left_unchecked), Toast.LENGTH_SHORT).show(); - PreferenceManager.getDefaultSharedPreferences(ctx) - .edit() - .putBoolean("pref_do_notifications", false) - .commit(); - } - break; - case NOTIFICATION_LISTENER_OFF: - Log.d("F-oAR", "return from unchecking the box"); - notification_settings_ongoing = false; - if (Functions.Is.service_running(ctx, NotificationService.class)) { - Toast.makeText(ctx, ctx.getString(R.string.notif_left_checked), Toast.LENGTH_SHORT).show(); - PreferenceManager.getDefaultSharedPreferences(ctx) - .edit() - .putBoolean("pref_do_notifications", true) - .commit(); - } - break; - } - } - - /** - * Invoked via the AdminReceiver when the admin status changes. - * @param ctx Application context. - * @param admin Is the admin permission granted. - */ - public static void device_admin_status(Context ctx, boolean admin) { - - Log.d("F.Evt.dev_adm_status", "Device admin status called with admin status: " + admin); - - Toast.makeText(ctx, ctx.getString(admin ? R.string.admin_granted : R.string.admin_revoked), Toast.LENGTH_SHORT).show(); - - //FIXME none of the below seems to actually be necessary? - /*if (admin) { - if (PreferenceManager.getDefaultSharedPreferences(ctx).getBoolean("pref_enabled", false) && Is.cover_closed(ctx)) { - Actions.close_cover(ctx); - } - } else { - Actions.stop_service(ctx); - PreferenceManager.getDefaultSharedPreferences(ctx) - .edit() - .putBoolean("pref_enabled", false) - .commit(); - }*/ - - - } - - /** - * Setter method for the cover closed state. - * @param closed Is the cover closed - */ - public static void set_cover(boolean closed) { - cover_closed = closed; - } - - - /** - * Receives the value of the proximity sensor and reacts accordingly to update the cover state. - * @param ctx Application context. - * @param value Value of the proximity sensor. - */ - public static void proximity(Context ctx, float value) { - - Log.d("F.Evt.proximity", "Proximity method called with value: " + value + " ,whilst cover_closed is: " + cover_closed); - - if (value > 0) { - if (cover_closed) { - if (!Functions.Is.cover_closed(ctx)) { - //proximity false (>0) and cover open - take open_cover action - Actions.open_cover(ctx); - } - } - } else { - if (!cover_closed) { - if (Functions.Is.cover_closed(ctx)) { - //proximity true (<=0) and cover closed - take close_cover action - Actions.close_cover(ctx); - } - } - } - //Log.d(ctx.getString(R.string.app_name), String.format("cover_closed = %b", cover_closed)); - } - - public static void headset(final Context ctx, int state) { - if (state != 0) { - // headset was just inserted - if (Is.cover_closed(ctx)) { - new Handler().postDelayed(new Runnable() { - @Override - public void run() { - ctx.getApplicationContext().startActivity(new Intent(ctx.getApplicationContext(), DefaultActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); - } - }, 500); // FIXME this is by far the biggest hack yet - } - } - - if (defaultActivity.on_screen) { - defaultActivity.refreshDisplay(); - } - } - - public static void incoming_call(final Context ctx, String number) { - Log.d("phone", "call from " + number); - if (Functions.Is.cover_closed(ctx)) { - Log.d("phone", "but the screen is closed. screen my calls"); - - //if the cover is closed then - //we want to pop this activity up over the top of the dialer activity - //to guarantee that we need to hold off until the dialer activity is running - //a 1 second delay seems to allow this - DefaultActivity.phone_ringing = true; - DefaultActivity.call_from = number; - - Timer timer = new Timer(); - timer.schedule(new TimerTask() { - @Override - public void run() { - Intent intent = new Intent(ctx, DefaultActivity.class); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_CLEAR_TOP - | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); - intent.setAction(Intent.ACTION_MAIN); - ctx.startActivity(intent); - Actions.enableCoverTouch(ctx, true); - - //Util.rise_and_shine(ctx); // make sure the screen is on (Removed for Testing) - } - }, 800); - - // We must stop TimerTask during an incoming call, and we must be sure that - // timerTask.cancel will be executed only when the screen is on - Timer timer2 = new Timer(); - timer2.schedule(new TimerTask() { - @Override - public void run() { - if (Functions.Actions.timerTask != null) { - Functions.Actions.timerTask.cancel();} - } - - }, 2500); - - /* - new Handler().postDelayed(new Runnable() { - @Override - public void run() { - Process process; - try { - process = Runtime.getRuntime().exec(new String[]{ "su","-c","input keyevent 6"}); - process.waitFor(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - } - }, 500); - */ - - } - } - - public static void call_finished(Context ctx) { - Log.d("phone", "call is over, cleaning up"); - DefaultActivity.phone_ringing = false; - ((TextView)defaultActivity.findViewById(R.id.call_from)).setText(ctx.getString(R.string.unknown_caller)); - Actions.close_cover(ctx); - } - } - - /** - * Contains methods to check the state - */ - public static class Is { - - public static boolean torchIsOn = false; - - /** - * Is the cover closed. - * @param ctx Application context. - * @return Is the cover closed. - */ - public static boolean cover_closed(Context ctx) { - - Log.d("F.Is.cover_closed", "Is cover closed called."); - - String status = ""; - try { - Scanner sc = new Scanner(new File(ctx.getString(R.string.hall_file))); - status = sc.nextLine(); - sc.close(); - } catch (FileNotFoundException e) { - Log.e(ctx.getString(R.string.app_name), "Hall effect sensor device file not found!"); - } - - boolean isClosed = (status.compareTo("CLOSE") == 0); - - Log.d("F.Is.cover_closed","Cover closed state is: " + true); - - return isClosed; - } - - - /** - * Is the service running. - * @param ctx Application context. - * @return Is the cover closed. - */ - public static boolean service_running(Context ctx, Class svc) { - - Log.d("F.Is.service_running", "Is service running called."); - - ActivityManager manager = (ActivityManager) ctx.getSystemService(Context.ACTIVITY_SERVICE); - for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { - if (svc.getName().equals(service.service.getClassName())) { - // the service is running - Log.d("F.Is.service_running", "The " + svc.getName() + " is running."); - return true; - } - } - // the service must not be running - Log.d("F.Is.service_running", "The " + svc.getName() + " service is NOT running."); - return false; - } - - - /** - * Is the specified widget enabled - * @param ctx Application context - * @param widgetType Widget type to check for - * @return True if it is, False if not - */ - public static boolean widget_enabled(Context ctx, String widgetType) { - - Log.d("F.Is.wid_enabled", "Is default widget enabled called with widgetType: " + widgetType); - - boolean widgetEnabled = Functions.hmAppWidgetManager.doesWidgetExist(widgetType); - - Log.d("F.Is.wid_enabled", widgetType + " widget enabled state is: " + widgetEnabled); - - return widgetEnabled; - } - - public static boolean SystemApp(Context ctx) { - return (ctx.getApplicationInfo().flags & (ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0; - } - - } - - public static class Util { - // from http://stackoverflow.com/questions/3712112/search-contact-by-phone-number - public static String getContactName(Context ctx, String number) { - - if (number.equals("")) return ""; - - Log.d("phone", "looking up " + number + "..."); - - Uri uri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number)); - String name = number; - - ContentResolver contentResolver = ctx.getContentResolver(); - Cursor contactLookup = contentResolver.query(uri, new String[] {BaseColumns._ID, - ContactsContract.PhoneLookup.DISPLAY_NAME }, null, null, null); - - try { - if (contactLookup != null && contactLookup.getCount() > 0) { - contactLookup.moveToNext(); - name = contactLookup.getString(contactLookup.getColumnIndex(ContactsContract.Data.DISPLAY_NAME)); - //String contactId = contactLookup.getString(contactLookup.getColumnIndex(BaseColumns._ID)); - } - } finally { - if (contactLookup != null) { - contactLookup.close(); - } - } - - Log.d("phone", "...result is " + name); - return name; - } - - public static void rise_and_shine(Context ctx) { - //FIXME Would be nice to remove the deprecated FULL_WAKE_LOCK if possible - Log.d("F.Util.rs", "aww why can't I hit snooze"); - PowerManager pm = (PowerManager) ctx.getSystemService(Context.POWER_SERVICE); - @SuppressWarnings("deprecation") - PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, ctx.getString(R.string.app_name)); - wl.acquire(); - wl.release(); - } - } - - public static class TorchActions { - - /** - * With this non-CM users can use torch button in HallMonitor. - * Should (Hopefully) work on every device with SystemFeature FEATURE_CAMERA_FLASH - * This code has been tested on I9505 jflte with ParanoidAndroid 4.4 rc2 - */ - - // Turn On Flash - public static void turnOnFlash() { - camera = Camera.open(); - Parameters p = camera.getParameters(); - p.setFlashMode(Parameters.FLASH_MODE_TORCH); - camera.setParameters(p); - camera.startPreview(); - flashIsOn = true; - Log.d("torch", "turned on!"); - } - - // Turn Off Flash - public static void turnOffFlash() { - Parameters p = camera.getParameters(); - p.setFlashMode(Parameters.FLASH_MODE_OFF); - camera.setParameters(p); - camera.stopPreview(); - flashIsOn = false; - // Be sure to release the camera when the flash is turned off - if (camera != null) { - camera.release(); - camera = null; - Log.d("torch", "turned off and camera released!"); - } - } - - public static void deviceHasFlash(Context ctx) { - deviceHasFlash = ctx.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH); - } - } -} diff --git a/src/org/durka/hallmonitor/HMAppWidgetManager.java b/src/org/durka/hallmonitor/HMAppWidgetManager.java index 409342b..75b8403 100644 --- a/src/org/durka/hallmonitor/HMAppWidgetManager.java +++ b/src/org/durka/hallmonitor/HMAppWidgetManager.java @@ -2,214 +2,295 @@ import java.util.HashMap; -import android.app.Activity; import android.appwidget.AppWidgetHost; import android.appwidget.AppWidgetHostView; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProviderInfo; -import android.content.Context; import android.content.Intent; import android.os.Bundle; -import android.preference.PreferenceManager; import android.util.Log; /** - * The purpose of this Class is to provide management capabilities for the app widgets - * that get added to the HallMonitor application. + * The purpose of this Class is to provide management capabilities for the app + * widgets that get added to the HallMonitor application. + * * @author nwalters - * + * */ public class HMAppWidgetManager { + private static final String LOG_TAG = "Hall.HMAWM"; - //map of our selected widgets - private HashMap widgetsMap = new HashMap(); - - //track which widget we are currently dealing with - holds state across the events firing - //this is a bit clunky, but there's no need to worry about thread safety so should be fine - public String currentWidgetType; - - //app widget management classes we need - public AppWidgetManager mAppWidgetManager; - public AppWidgetHost mAppWidgetHost; - - //default constructor - public HMAppWidgetManager() { - //nothing to do - Log.d("HMAWM.constructor","HMAppWidgetManager instantiated."); - } - - /** - * Kick off the widget picker dialog - * @param act The Activity to use as the context for these actions - * @param widgetType The type of widget (e.g. 'default', 'media', 'notification' etc.) - */ - public void register_widget(Activity act, String widgetType) { - - Log.d("HMAWM.register_widget","Register widget called with type: " + widgetType); - - //if we haven't yet created an app widget manager and app widget host instance then do so - if (mAppWidgetManager == null) mAppWidgetManager = AppWidgetManager.getInstance(act); - if (mAppWidgetHost == null) mAppWidgetHost = new AppWidgetHost(act, R.id.APPWIDGET_HOST_ID); - - //get an id for our app widget + private final CoreStateManager mStateManager; + + // map of our selected widgets + private final HashMap widgetsMap = new HashMap(); + + // app widget management classes we need + private AppWidgetManager mAppWidgetManager; + private AppWidgetHost mAppWidgetHost; + + // default constructor + public HMAppWidgetManager(CoreStateManager stateManager) { + mStateManager = stateManager; + + if (mAppWidgetManager == null) { + mAppWidgetManager = AppWidgetManager.getInstance(CoreStateManager + .getContext()); + } else { + Log.e(LOG_TAG + ".constructor", + "HMAppWidgetManager uneable to get AppWidgetManager."); + } + if (mAppWidgetHost == null) { + mAppWidgetHost = new AppWidgetHost(CoreStateManager.getContext(), + R.id.APPWIDGET_HOST_ID); + } else { + Log.e(LOG_TAG + ".constructor", + "HMAppWidgetManager uneable to get AppWidgetHost."); + } + + Log.d(LOG_TAG + ".constructor", "HMAppWidgetManager instantiated."); + } + + /** + * Kick off the widget picker dialog + * + * @param act + * The Activity to use as the context for these actions + * @param widgetType + * The type of widget (e.g. 'default', 'media', 'notification' + * etc.) + */ + public void registerWidget(String widgetType) { + + Log.d(LOG_TAG + ".register_widget", + "Register widget called with type: " + widgetType); + + // get an id for our app widget int appWidgetId = mAppWidgetHost.allocateAppWidgetId(); - PreferenceManager.getDefaultSharedPreferences(act).edit() - .putInt(widgetType + "_widget_id", appWidgetId) - .commit(); - - Log.d("HMAWM.register_widget","appWidgetId allocated: " + appWidgetId); - - //create an intent to allow us to fire up the widget picker - Intent pickIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_PICK); - pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); - - //store our widgetType so we know what we are doing when the call back comes back - currentWidgetType = widgetType; - - //kick off the widget picker, the call back will be picked up in Functions.Events - Functions.widget_settings_ongoing = true; - act.startActivityForResult(pickIntent, Functions.REQUEST_PICK_APPWIDGET); - + mStateManager.getPreference().edit() + .putInt(widgetType + "_widget_id", appWidgetId).commit(); + + Log.d(LOG_TAG + ".register_widget", "appWidgetId allocated: " + + appWidgetId); + + // kick off the widget picker, the call back will be picked up in + mStateManager.setWidgetSettingsOngoing(true); + CoreStateManager.getContext().startActivity( + new Intent(CoreStateManager.getContext(), Configuration.class) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_NO_ANIMATION + | Intent.FLAG_ACTIVITY_CLEAR_TOP + | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)); + Log.d(LOG_TAG + ".register_widget", "Started configuration activity."); + + // create an intent to allow us to fire up the widget picker + Intent pickIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_PICK); + pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); + pickIntent.putExtra(CoreApp.EXTRA_APPWIDGET_TYPE, widgetType); + + if (mStateManager.getConfigurationActivity() != null) { + mStateManager.getConfigurationActivity().startActivityForResult( + pickIntent, CoreApp.REQUEST_PICK_APPWIDGET); + } } - + /** * Launch into configuration dialog if required - * @param data Intent payload, needed for getting app widget id - * @param ctx Calling context + * + * @param data + * Intent payload, needed for getting app widget id + * @param ctx + * Calling context */ - public void configureWidget(Intent data, Context ctx) { - //get the app widget id from the call back - Bundle extras = data.getExtras(); - int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, -1); - - Log.d("HMAWM.configureWidget","Configure widget called with id: " + appWidgetId); - - //use the app widget id to get the app widget info - AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId); - - //check if we need to configure - if (appWidgetInfo.configure != null) { - - Log.d("HMAWM.configureWidget","This is a configurable widget, launching widget configuraiton activity"); - - //we do so launch into configuration dialog - Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE); - intent.setComponent(appWidgetInfo.configure); - intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); - Functions.widget_settings_ongoing = true; - ((Activity)ctx).startActivityForResult(intent, Functions.REQUEST_CONFIGURE_APPWIDGET); - } else { - - Log.d("HMAWM.configureWidget","This is NOT a configurable widget."); - - //we don't, just create it already - createWidget(data, ctx); - } + public void configureWidget(String widgetType, Intent data) { + // get the app widget id from the call back + Bundle extras = data.getExtras(); + int appWidgetId = extras + .getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, -1); + + Log.d(LOG_TAG + ".configureWidget", "Configure widget called with id: " + + appWidgetId); + + // use the app widget id to get the app widget info + AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager + .getAppWidgetInfo(appWidgetId); + + // check if we need to configure + if (appWidgetInfo.configure != null) { + + Log.d(LOG_TAG + ".configureWidget", + "This is a configurable widget, launching widget configuraiton activity"); + + mStateManager.setWidgetSettingsOngoing(true); + CoreStateManager + .getContext() + .startActivity( + new Intent(CoreStateManager.getContext(), + Configuration.class) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_NO_ANIMATION + | Intent.FLAG_ACTIVITY_CLEAR_TOP + | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)); + Log.d(LOG_TAG + ".register_widget", + "Started configuration activity."); + + // we do so launch into configuration dialog + Intent intent = new Intent( + AppWidgetManager.ACTION_APPWIDGET_CONFIGURE); + intent.setComponent(appWidgetInfo.configure); + intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); + intent.putExtra(CoreApp.EXTRA_APPWIDGET_TYPE, widgetType); + + if (mStateManager.getConfigurationActivity() != null) { + mStateManager.getConfigurationActivity() + .startActivityForResult(intent, + CoreApp.REQUEST_CONFIGURE_APPWIDGET); + } + } else { + + Log.d(LOG_TAG + ".configureWidget", + "This is NOT a configurable widget."); + + // we don't, just create it already + createWidget(widgetType, data); + } } - - + /** * Create the AppWidgetHostView representing our widget and store in our map - * @param data Intent payload, needed for getting app widget id - * @param ctx Calling context + * + * @param data + * Intent payload, needed for getting app widget id + * @param ctx + * Calling context */ - public void createWidget(Intent data, Context ctx) { - //get the app widget id from the call back - Bundle extras = data.getExtras(); - int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, -1); - - Log.d("HMAWM.createWidget","Create widget called with id: " + appWidgetId); - - //FIXME put this in the constructor?? - //if we haven't yet created an app widget manager and app widget host instance then do so - if (mAppWidgetManager == null) mAppWidgetManager = AppWidgetManager.getInstance(ctx); - if (mAppWidgetHost == null) mAppWidgetHost = new AppWidgetHost(ctx, R.id.APPWIDGET_HOST_ID); - - //use the app widget id to get the app widget info - AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId); - - //debug out all the info about the widget - if (Log.isLoggable("HMAWM.createWidget", Log.DEBUG)){ - Log.d("HMAWM.createWidget", "appWidgetInfo Label: " + appWidgetInfo.label); - Log.d("HMAWM.createWidget", "appWidgetInfo minHeight: " + appWidgetInfo.minHeight); - Log.d("HMAWM.createWidget", "appWidgetInfo minResizeWidth: " + appWidgetInfo.minResizeHeight); - Log.d("HMAWM.createWidget", "appWidgetInfo minWidth: " + appWidgetInfo.minWidth); - Log.d("HMAWM.createWidget", "appWidgetInfo minResizeWidth: " + appWidgetInfo.minResizeWidth); - Log.d("HMAWM.createWidget", "appWidgetInfo resizeMode: " + appWidgetInfo.resizeMode); - Log.d("HMAWM.createWidget", "appWidgetInfo updatePeriodMillis: " + appWidgetInfo.updatePeriodMillis); - Log.d("HMAWM.createWidget", "appWidgetInfo widgetCategory: " + appWidgetInfo.widgetCategory); - } - - //create the hostView - this effectively represents our widget - AppWidgetHostView hostView = mAppWidgetHost.createView(ctx, appWidgetId, appWidgetInfo); - //bizarrely this is needed to tell the hostView about the widget (again!) - hostView.setAppWidget(appWidgetId, appWidgetInfo); - - //store hostView into our widgets map for access later - widgetsMap.put(currentWidgetType, hostView); - - //start the widget listening - mAppWidgetHost.startListening(); - - Log.d("HMAWM.createWidget","Widget created and stored of type: " + currentWidgetType); - } - + public void createWidget(String widgetType, Intent data) { + // get the app widget id from the call back + Bundle extras = data.getExtras(); + int appWidgetId = extras + .getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, -1); + + Log.d(LOG_TAG + ".createWidget", "Create widget called with id: " + + appWidgetId); + + // use the app widget id to get the app widget info + AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager + .getAppWidgetInfo(appWidgetId); + + // debug out all the info about the widget + if (Log.isLoggable(LOG_TAG + ".createWidget", Log.DEBUG)) { + Log.d(LOG_TAG + ".createWidget", "appWidgetInfo Label: " + + appWidgetInfo.label); + Log.d(LOG_TAG + ".createWidget", "appWidgetInfo minHeight: " + + appWidgetInfo.minHeight); + Log.d(LOG_TAG + ".createWidget", "appWidgetInfo minResizeWidth: " + + appWidgetInfo.minResizeHeight); + Log.d(LOG_TAG + ".createWidget", "appWidgetInfo minWidth: " + + appWidgetInfo.minWidth); + Log.d(LOG_TAG + ".createWidget", "appWidgetInfo minResizeWidth: " + + appWidgetInfo.minResizeWidth); + Log.d(LOG_TAG + ".createWidget", "appWidgetInfo resizeMode: " + + appWidgetInfo.resizeMode); + Log.d(LOG_TAG + ".createWidget", + "appWidgetInfo updatePeriodMillis: " + + appWidgetInfo.updatePeriodMillis); + Log.d(LOG_TAG + ".createWidget", "appWidgetInfo widgetCategory: " + + appWidgetInfo.widgetCategory); + } + + // create the hostView - this effectively represents our widget + AppWidgetHostView hostView = mAppWidgetHost.createView( + CoreStateManager.getContext(), appWidgetId, appWidgetInfo); + // bizarrely this is needed to tell the hostView about the widget + // (again!) + hostView.setAppWidget(appWidgetId, appWidgetInfo); + + // store hostView into our widgets map for access later + widgetsMap.put(widgetType, hostView); + + // start the widget listening + mAppWidgetHost.startListening(); + + Log.d(LOG_TAG + ".createWidget", "Widget created and stored of type: " + + widgetType); + } + /** - * Remove the app widget ID as the user has cancelled the process at some point - * @param appWidgetId The app widget ID to remove + * Remove the app widget ID as the user has cancelled the process at some + * point + * + * @param appWidgetId + * The app widget ID to remove */ public void deleteAppWidgetId(int appWidgetId) { - - Log.d("HMAWM.deleteAppWidgetId","Deleting widget id: " + appWidgetId); - - //stop the widget listening + + Log.d(LOG_TAG + ".deleteAppWidgetId", "Deleting widget id: " + + appWidgetId); + + // stop the widget listening mAppWidgetHost.stopListening(); - + mAppWidgetHost.deleteAppWidgetId(appWidgetId); } - - + /** - * The user has decided they don't want to use the custom widget so let's get rid of it - * @param ctx The calling context - * @param widgetType The type of widget they are done with + * The user has decided they don't want to use the custom widget so let's + * get rid of it + * + * @param ctx + * The calling context + * @param widgetType + * The type of widget they are done with */ - public void unregister_widget(Context ctx, String widgetType) { - - Log.d("HMAWM.unregister_widget","Unregister widget called with type: " + widgetType); - + public void unregisterWidget(String widgetType) { + + Log.d(LOG_TAG + ".unregister_widget", + "Unregister widget called with type: " + widgetType); + widgetsMap.remove(widgetType); - - //FIXME: Should we also clear up the app widget ID? + mStateManager.getPreference().edit() + .putBoolean("pref_" + widgetType + "_widget", false) + .putInt(widgetType + "_widget_id", -1).commit(); } - + /** * Get the specified widget from the map - * @param widgetType The type of the widget to get + * + * @param widgetType + * The type of the widget to get * @return The stored widget */ public AppWidgetHostView getAppWidgetHostViewByType(String widgetType) { - - Log.d("HMAWM.getAppWidgetHostViewByType","Widget requested of type: " + widgetType); - - AppWidgetHostView thisWidget = widgetsMap.get(widgetType);; - - if (thisWidget == null) Log.w("HMAWM.getAppWidgetHostViewByType","Widget type does not exist in widget Map: " + widgetType); - + + Log.d(LOG_TAG + ".getAppWidgetHostViewByType", + "Widget requested of type: " + widgetType); + + mStateManager.createWidget(widgetType); + + AppWidgetHostView thisWidget = widgetsMap.get(widgetType); + ; + + if (thisWidget == null) { + Log.w(LOG_TAG + ".getAppWidgetHostViewByType", + "Widget type does not exist in widget Map: " + widgetType); + } + return thisWidget; } - - + /** * Get the specified widget from the map - * @param widgetType The type of the widget to get + * + * @param widgetType + * The type of the widget to get * @return The stored widget */ public boolean doesWidgetExist(String widgetType) { - - Log.d("HMAWM.doesWidgetExist","Checking for Widget of type: " + widgetType); - + + Log.d(LOG_TAG + ".doesWidgetExist", "Checking for Widget of type: " + + widgetType); + return (widgetsMap.get(widgetType) != null); } - + } diff --git a/src/org/durka/hallmonitor/HeadsetReceiver.java b/src/org/durka/hallmonitor/HeadsetReceiver.java deleted file mode 100644 index 6435286..0000000 --- a/src/org/durka/hallmonitor/HeadsetReceiver.java +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright 2013 Alex Burka - - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.durka.hallmonitor; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.util.Log; - -public class HeadsetReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context ctx, Intent intent) { - int state = intent.getExtras().getInt("state"); - Log.d("HR", "headset is " + (state == 0 ? "gone" : "here") + "!"); - Functions.Events.headset(ctx, state); - } -} diff --git a/src/org/durka/hallmonitor/NotificationAdapter.java b/src/org/durka/hallmonitor/NotificationAdapter.java index 22ebfdc..b113907 100644 --- a/src/org/durka/hallmonitor/NotificationAdapter.java +++ b/src/org/durka/hallmonitor/NotificationAdapter.java @@ -8,22 +8,25 @@ import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; -import android.widget.GridView; import android.widget.ImageView; +import android.widget.ImageView.ScaleType; public class NotificationAdapter extends BaseAdapter { - + + private final String LOG_TAG = "Hall.NA"; + private StatusBarNotification[] notifs; - private Context that; - + private final Context that; + public NotificationAdapter(Context ctx, StatusBarNotification[] n) { that = ctx; notifs = n; } - + public void update(StatusBarNotification[] n) { notifs = n; - Log.d("NA.upd", "update: " + Integer.toString(n.length) + " notifications"); + Log.d(LOG_TAG + ".upd", "update: " + Integer.toString(n.length) + + " notifications"); } @Override @@ -45,14 +48,19 @@ public long getItemId(int position) { public View getView(int position, View convert, ViewGroup parent) { ImageView view; if (convert != null) { - view = (ImageView)convert; + view = (ImageView) convert; } else { view = new ImageView(that); - int size = (int) that.getResources().getDimension(R.dimen.icon_dimension); - view.setLayoutParams(new GridView.LayoutParams(size, size)); - view.setPadding(0, 0, 0, 0); + // int size = (int) + // that.getResources().getDimension(R.dimen.icon_dimension); + // view.setLayoutParams(new GridView.LayoutParams(size, size)); + view.setScaleType(ScaleType.CENTER_INSIDE); try { - view.setImageDrawable(that.createPackageContext(notifs[position].getPackageName(), 0).getResources().getDrawable(notifs[position].getNotification().icon)); + view.setImageDrawable(that + .createPackageContext( + notifs[position].getPackageName(), 0) + .getResources() + .getDrawable(notifs[position].getNotification().icon)); } catch (NotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -63,7 +71,6 @@ public View getView(int position, View convert, ViewGroup parent) { } return view; - } - + } } diff --git a/src/org/durka/hallmonitor/NotificationService.java b/src/org/durka/hallmonitor/NotificationService.java index ebd4fe0..bc5b7dc 100644 --- a/src/org/durka/hallmonitor/NotificationService.java +++ b/src/org/durka/hallmonitor/NotificationService.java @@ -17,56 +17,62 @@ import java.util.ArrayList; import java.util.List; -import android.util.Log; +import android.content.Intent; import android.service.notification.NotificationListenerService; import android.service.notification.StatusBarNotification; - +import android.support.v4.content.LocalBroadcastManager; +import android.util.Log; public class NotificationService extends NotificationListenerService { - + + private final String LOG_TAG = "Hall.NS"; public static NotificationService that = null; - + private LocalBroadcastManager mLocalBroadcastManager; + @SuppressWarnings("serial") - private final List blacklist = new ArrayList() {{ + private final List blacklist = new ArrayList() { + { add("net.cactii.flash2"); // we have our own flashlight UI - add("android"); // this covers the keyboard selection notification, but does it clobber others too? TODO - }}; - + add("android"); // this covers the keyboard selection notification, + // but does it clobber others too? TODO + } + }; + @Override public void onCreate() { - Log.d("NS-oC", "ohai"); + Log.d(LOG_TAG + ".oC", "ohai"); that = this; + mLocalBroadcastManager = LocalBroadcastManager.getInstance(this); } - + @Override public void onDestroy() { - Log.d("NS-oD", "kthxbai"); + Log.d(LOG_TAG + ".oD", "kthxbai"); that = null; } - + @Override public void onNotificationPosted(StatusBarNotification sbn) { - Log.d("NS-oNP", "notification posted: " + sbn.toString()); - if (DefaultActivity.on_screen) { - Functions.Actions.refresh_notifications(); - } + Log.d(LOG_TAG + ".oNP", "notification posted: " + sbn.toString()); + Intent mIntent = new Intent(CoreApp.DA_ACTION_NOTIFICATION_REFRESH); + mLocalBroadcastManager.sendBroadcastSync(mIntent); } @Override public void onNotificationRemoved(StatusBarNotification sbn) { - Log.d("NS-oNR", "notification removed: " + sbn.toString()); - if (DefaultActivity.on_screen) { - Functions.Actions.refresh_notifications(); - } + Log.d(LOG_TAG + ".oNR", "notification removed: " + sbn.toString()); + Intent mIntent = new Intent(CoreApp.DA_ACTION_NOTIFICATION_REFRESH); + mLocalBroadcastManager.sendBroadcastSync(mIntent); } - + @Override public StatusBarNotification[] getActiveNotifications() { StatusBarNotification[] notifs = super.getActiveNotifications(); - - List acc = new ArrayList(notifs.length); + + List acc = new ArrayList( + notifs.length); for (StatusBarNotification sbn : notifs) { - Log.d("NS-gAN", sbn.getPackageName()); + Log.d(LOG_TAG + ".gAN", sbn.getPackageName()); if (!blacklist.contains(sbn.getPackageName())) { acc.add(sbn); } diff --git a/src/org/durka/hallmonitor/PreferenceFragmentLoader.java b/src/org/durka/hallmonitor/PreferenceFragmentLoader.java index c777c95..d013802 100644 --- a/src/org/durka/hallmonitor/PreferenceFragmentLoader.java +++ b/src/org/durka/hallmonitor/PreferenceFragmentLoader.java @@ -14,13 +14,13 @@ */ package org.durka.hallmonitor; -import org.durka.hallmonitor.Functions.TorchActions; - -import eu.chainfire.libsuperuser.Shell; import android.app.Activity; +import android.app.AlarmManager; import android.app.AlertDialog; +import android.app.PendingIntent; import android.content.Context; import android.content.DialogInterface; +import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; @@ -28,7 +28,6 @@ import android.graphics.Color; import android.os.AsyncTask; import android.os.Bundle; -import android.os.SystemClock; import android.preference.CheckBoxPreference; import android.preference.ListPreference; import android.preference.Preference; @@ -41,321 +40,588 @@ import android.view.View; import android.view.View.OnClickListener; import android.widget.Toast; +import eu.chainfire.libsuperuser.Shell; + +public class PreferenceFragmentLoader extends PreferenceFragment implements + SharedPreferences.OnSharedPreferenceChangeListener { + private final String LOG_TAG = "Hall.PFL"; + + private boolean mDebug = false; + private int mAboutClicked = 0; + private final int mAboutClickCount = 7; + + private CoreStateManager mStateManager; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Log.d(LOG_TAG + ".oC", ""); + + mStateManager = ((CoreApp) getActivity().getApplicationContext()) + .getStateManager(); -public class PreferenceFragmentLoader extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener { - private final String LOG_TAG = "PreferenceFragmentLoader"; - - private boolean mDebug = false; - private int mAboutClicked = 0; - private int mAboutClickCount = 7; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - Log.d(LOG_TAG, "PFL-oC"); - - try { - final String resourceName = getArguments().getString("resource", ""); - Log.d(LOG_TAG, "loading preferences from " + resourceName + ".xml"); - - Context context = getActivity().getApplicationContext(); - - // debug - mDebug = getPreferenceManager().getSharedPreferences().getBoolean("pref_dev_opts_debug", mDebug); - if (mDebug) - Toast.makeText(getActivity(), "debug is enabled!", Toast.LENGTH_LONG).show(); - - final int resourceId = context.getResources().getIdentifier(resourceName, "xml", context.getPackageName()); - - PreferenceManager.setDefaultValues(getActivity(), resourceId, false); - addPreferencesFromResource(resourceId); - } catch (Exception e) { - Log_d(LOG_TAG, "onCreate: exception occurred! " + e.getMessage()); - } - - // setup about preference for debug - Preference about = findPreference("pref_about"); - if (about != null) { - // init onClick listener - about.setEnabled(true); - about.setSelectable(true); - about.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - mAboutClicked += 1; - if (mAboutClicked == mAboutClickCount) { - mAboutClicked = 0; - SharedPreferences prefs = getPreferenceManager().getSharedPreferences(); - mDebug = !prefs.getBoolean("pref_dev_opts_debug", false); // toggle debug - prefs.edit().putBoolean("pref_dev_opts_debug", mDebug).commit(); - Toast.makeText(getActivity(), "debug is " + (prefs.getBoolean("pref_dev_opts_debug", false) ? "enabled" : "disabled") + " now!", Toast.LENGTH_LONG).show(); - } - - return true; - } - }); - - // mask text as disabled - about.setTitle(getTextDisabledFormatted(about.getTitle())); - about.setSummary(getTextDisabledFormatted(about.getSummary())); - } - } - - @Override - public void onResume() { - super.onResume(); - Log_d(LOG_TAG, "onResume: "); - - SharedPreferences prefs = getPreferenceManager().getSharedPreferences(); - - try { - Activity act = getActivity(); - PackageInfo info = act.getPackageManager().getPackageInfo(act.getPackageName(), 0); - - Log.d(LOG_TAG, "versionCode = " + info.versionCode); - - int old_version = prefs.getInt("version", 3); - if (old_version < info.versionCode) { - prefs.edit() - .putInt("version", info.versionCode) - .commit(); - - Log.d(LOG_TAG, "stored version code"); - } - - if (old_version < 5) { - new AlertDialog.Builder(act) - .setMessage(String.format(getResources().getString(R.string.firstrun_message), info.versionName)) - .setPositiveButton(R.string.firstrun_ok, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - // User clicked OK button - } - }) - .create() - .show(); - } + try { + final String resourceName = getArguments() + .getString("resource", ""); + Log.d(LOG_TAG + ".oC", "loading preferences from " + resourceName + + ".xml"); + + Context context = CoreStateManager.getContext(); + + // debug + mDebug = getPreferenceManager().getSharedPreferences().getBoolean( + "pref_dev_opts_debug", mDebug); + if (mDebug) { + Toast.makeText(getActivity(), "debug is enabled!", + Toast.LENGTH_LONG).show(); + } + + final int resourceId = context.getResources().getIdentifier( + resourceName, "xml", context.getPackageName()); + + PreferenceManager + .setDefaultValues(getActivity(), resourceId, false); + addPreferencesFromResource(resourceId); + } catch (Exception e) { + Log_d(LOG_TAG + ".oC", "exception occurred! " + e.getMessage()); + } + + // setup about preference for debug + Preference about = findPreference("pref_about"); + if (about != null) { + // init onClick listener + about.setEnabled(true); + about.setSelectable(true); + about.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + mAboutClicked += 1; + if (mAboutClicked == mAboutClickCount) { + mAboutClicked = 0; + SharedPreferences prefs = getPreferenceManager() + .getSharedPreferences(); + mDebug = !prefs + .getBoolean("pref_dev_opts_debug", false); // toggle + // debug + prefs.edit().putBoolean("pref_dev_opts_debug", mDebug) + .commit(); + Toast.makeText( + getActivity(), + "debug is " + + (prefs.getBoolean( + "pref_dev_opts_debug", false) ? "enabled" + : "disabled") + " now!", + Toast.LENGTH_LONG).show(); + } + + return true; + } + }); + + // mask text as disabled + about.setTitle(getTextDisabledFormatted(about.getTitle())); + about.setSummary(getTextDisabledFormatted(about.getSummary())); + } + } + + @Override + public void onResume() { + super.onResume(); + Log_d(LOG_TAG + ".oR", "resuming"); + + SharedPreferences prefs = getPreferenceManager().getSharedPreferences(); + + try { + Activity act = getActivity(); + PackageInfo info = act.getPackageManager().getPackageInfo( + act.getPackageName(), 0); + + Log.d(LOG_TAG + ".oR", "versionCode = " + info.versionCode); + + int old_version = prefs.getInt("version", 3); + if (old_version < info.versionCode) { + prefs.edit().putBoolean("pref_default_widget", false) + .putBoolean("pref_media_widget", false) + .putInt("default_widget_id", -1) + .putInt("media_widget_id", -1) + .putInt("version", info.versionCode).commit(); + + if (prefs.getBoolean("pref_do_notifications", false)) { + doNotifications(getActivity(), true); + } + + if (prefs.getBoolean("pref_lockmode", false)) { + mStateManager.requestAdmin(); + } + + Log.d(LOG_TAG + ".oR", "stored version code"); + } + + if (old_version < 5) { + new AlertDialog.Builder(act) + .setMessage( + String.format( + getResources().getString( + R.string.firstrun_message), + info.versionName)) + .setPositiveButton(R.string.firstrun_ok, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, + int id) { + // User clicked OK button + } + }).create().show(); + } } catch (NameNotFoundException e) { // this can't happen } - prefs.registerOnSharedPreferenceChangeListener(this); - - prefs.edit() - .putBoolean("pref_enabled", Functions.Is.service_running(getActivity(), ViewCoverHallService .class) || Functions.Is.service_running(getActivity(), ViewCoverProximityService.class)) - .putBoolean("pref_do_notifications", Functions.Is.service_running(getActivity(), NotificationService.class)) - //.putBoolean("pref_default_widget", Functions.Is.widget_enabled(getActivity(), "default")) - //.putBoolean("pref_media_widget", Functions.Is.widget_enabled(getActivity(), "media")) - .commit(); - - // phone control - enablePhoneScreen(prefs); - updatePhoneControlTtsDelay(prefs); - - } - - @Override - public void onPause() { - super.onPause(); - Log_d(LOG_TAG, "onPause: "); - - } - - @Override - public void onDestroy() { - super.onDestroy(); - Log_d(LOG_TAG, "onDestroy: "); - - getPreferenceManager().getSharedPreferences() - .unregisterOnSharedPreferenceChangeListener(this); - } - - @Override - public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { - Log_d(LOG_TAG + "-oSPC", "changed key " + key); - - // update display - if (findPreference(key) instanceof CheckBoxPreference) { - Log.d(LOG_TAG + "-oSPC", "toggling check box"); - ((CheckBoxPreference)findPreference(key)).setChecked(prefs.getBoolean(key, false)); - } else if (findPreference(key) instanceof PreferenceSwitchable) { - Log.d(LOG_TAG + "-oSPC", "toggling switch"); - ((PreferenceSwitchable)findPreference(key)).setChecked(prefs.getBoolean(key, false)); - } - - // if the service is being enabled/disabled the key will be pref_enabled - if (key.equals("pref_enabled")) { - - Log.d(LOG_TAG, "pref_enabled is now " + prefs.getBoolean(key, false)); - - if (prefs.getBoolean(key, false)) { - if(prefs.getBoolean("pref_runasroot", false)) { - AsyncSuAvailable localSuAvailable = new AsyncSuAvailable(); - localSuAvailable.execute(); - } - Functions.Actions.start_service(getActivity()); - } else { - Functions.Actions.stop_service(getActivity()); - } - - // if the default screen widget is being enabled/disabled the key will be pref_default_widget - } else if (key.equals("pref_default_widget")) { - - if (prefs.getBoolean(key, false) && !Functions.Is.widget_enabled(getActivity(), "default")) { - Functions.Actions.register_widget(getActivity(), "default"); - } else if (!prefs.getBoolean(key, false) && Functions.Is.widget_enabled(getActivity(), "default")) { - Functions.Actions.unregister_widget(getActivity(), "default"); - } - - // if the media screen widget is being enabled/disabled the key will be pref_media_widget - } else if (key.equals("pref_media_widget")) { - - if (prefs.getBoolean(key, false) && !Functions.Is.widget_enabled(getActivity(), "media")) { - Functions.Actions.register_widget(getActivity(), "media"); - } else if (!prefs.getBoolean(key, false) && Functions.Is.widget_enabled(getActivity(), "media")) { - Functions.Actions.unregister_widget(getActivity(), "media"); - } - - } else if (key.equals("pref_runasroot")) { - - AsyncSuAvailable localSuAvailable = new AsyncSuAvailable(); - localSuAvailable.execute(); - - } else if (key.equals("pref_realhall")) { - Functions.Actions.stop_service(getActivity(), true); - SystemClock.sleep(1000); - Functions.Actions.start_service(getActivity()); - - } else if (key.equals("pref_do_notifications")) { - Functions.Actions.do_notifications(getActivity(), prefs.getBoolean(key, false)); - // if the flash controls are being enabled/disabled the key will be pref_widget - } else if (key.equals("pref_flash_controls")) { - - if (prefs.getBoolean("pref_flash_controls_alternative", true) ) {Toast.makeText(getActivity(), getString(R.string.alternative_torch_enabled), Toast.LENGTH_SHORT).show(); - prefs.edit().putBoolean(key, false).commit(); - } else if (prefs.getBoolean(key, false) ) { - try { - PackageManager packageManager = getActivity().getPackageManager(); - packageManager.getApplicationLogo("net.cactii.flash2"); - } catch (PackageManager.NameNotFoundException nfne) { - // if the app isn't installed, just refuse to set the preference - Toast.makeText(getActivity(), getString(R.string.no_torch_app), Toast.LENGTH_SHORT).show(); - prefs.edit().putBoolean(key, false).commit(); - } - } - // if the flash controls are being enabled/disabled the key will be pref_widget - } else if (key.equals("pref_flash_controls_alternative")) { - - if (prefs.getBoolean("pref_flash_controls", true) ) {Toast.makeText(getActivity(), getString(R.string.default_torch_enabled), Toast.LENGTH_SHORT).show(); - prefs.edit().putBoolean(key, false).commit(); - } else if (prefs.getBoolean(key, false) ) { - TorchActions.deviceHasFlash(getActivity()); - if (Functions.deviceHasFlash) { - prefs.edit().putBoolean(key, true).commit(); - } else { - // if the device does not have camera flash feature refuse to set the preference - Toast.makeText(getActivity(), getString(R.string.no_torch), Toast.LENGTH_SHORT).show(); - prefs.edit().putBoolean(key, false).commit(); - } - } - // preferences_phone - } else if (key.equals("pref_phone_controls_tts_delay")) { - updatePhoneControlTtsDelay(prefs); - } - - // phone control - enablePhoneScreen(prefs); - } - - private void updatePhoneControlTtsDelay(SharedPreferences prefs) { - Preference preference = findPreference("pref_phone_controls_tts_delay"); - - if (preference != null && (preference instanceof ListPreference)) { - preference.setSummary(((ListPreference)preference).getEntry()); - } - } - - private void enablePhoneScreen(SharedPreferences prefs) { - boolean phoneControlState = prefs.getBoolean("pref_enabled", false) && prefs.getBoolean("pref_runasroot", false); - boolean phoneControlConfig = prefs.getBoolean("pref_phone_controls", false); - Preference phoneControl = findPreference("pref_phone_controls_user"); - - if (phoneControlConfig != phoneControlState && phoneControl != null) - phoneControl.setEnabled(phoneControlState); - if (phoneControlConfig != (phoneControlState && prefs.getBoolean("pref_phone_controls_user", false))) - prefs.edit().putBoolean("pref_phone_controls", !phoneControlConfig).commit(); - } - - private void Log_d(String tag, String message) { - if (mDebug) - Log.d(tag, message); - } - - private SpannableString getTextDisabledFormatted(CharSequence text) { - // TODO: read default text color - int defaultTextColor = Color.BLACK; - - int alpha = Color.argb((int)(0.5f * 255), Color.red(defaultTextColor), Color.green(defaultTextColor), Color.blue(defaultTextColor)); - - SpannableString spannableString = new SpannableString(text); - spannableString.setSpan(new ForegroundColorSpan(alpha), 0, text.length(), 0); - - return spannableString; - } - - @Override - public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference pref) - { - super.onPreferenceTreeClick(screen, pref); - - if (pref != null && pref instanceof PreferenceScreen) { - // make the back button on the action bar work (why doesn't it work by default???) - // FIXME this is another hack - // thanks be to https://stackoverflow.com/questions/16374820/action-bar-home-button-not-functional-with-nested-preferencescreen - - final PreferenceScreen ps = (PreferenceScreen)pref; - if (ps.getDialog() != null) { - ps.getDialog().getActionBar().setDisplayHomeAsUpEnabled(true); - - // carefully walk up two levels from the home button - View v = ps.getDialog().findViewById(android.R.id.home); - if (v != null) - { - if (v.getParent() != null && v.getParent() instanceof View) { - v = (View)v.getParent(); - if (v.getParent() != null && v.getParent() instanceof View) { - v = (View)v.getParent(); - - // found the view we want, make it so - v.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View view) { - ps.getDialog().dismiss(); - } - - }); - } - } - } - } - } - - return false; - } - - private class AsyncSuAvailable extends AsyncTask { + prefs.registerOnSharedPreferenceChangeListener(this); + + prefs.edit() + .putBoolean("pref_enabled", + mStateManager.getServiceRunning(CoreService.class)) + .putBoolean( + "pref_do_notifications", + mStateManager + .getServiceRunning(NotificationService.class)) + .putBoolean( + "pref_realhall", + mStateManager + .getServiceRunning(ViewCoverHallService.class)) + .putBoolean( + "pref_proximity", + mStateManager + .getServiceRunning(ViewCoverProximityService.class)) + .commit(); + + setSystemApp(prefs); + + // Rebuild dependency + // RealHall + enableRealHall(prefs); + // Phone Control + enablePhoneScreen(prefs); + } + + @Override + public void onPause() { + super.onPause(); + Log_d(LOG_TAG + ".oP", "pausing"); + + } + + @Override + public void onDestroy() { + super.onDestroy(); + Log_d(LOG_TAG + ".oD", "destroying "); + + getPreferenceManager().getSharedPreferences() + .unregisterOnSharedPreferenceChangeListener(this); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { + Log_d(LOG_TAG + ".oSPC", "changed key " + key); + if (mStateManager.getDefaultActivityRunning()) { + mStateManager.closeDefaultActivity(); + } + + // update display + if (findPreference(key) instanceof CheckBoxPreference) { + Log.d(LOG_TAG + ".oSPC", "toggling check box"); + ((CheckBoxPreference) findPreference(key)).setChecked(prefs + .getBoolean(key, false)); + } else if (findPreference(key) instanceof PreferenceSwitchable) { + Log.d(LOG_TAG + ".oSPC", "toggling switch"); + ((PreferenceSwitchable) findPreference(key)).setChecked(prefs + .getBoolean(key, false)); + } + + // MAIN SCREEN + if (key.equals("pref_enabled")) { + Log.d(LOG_TAG + ".oSPC", + "pref_enabled is now " + prefs.getBoolean(key, false)); + + if (prefs.getBoolean(key, false)) { + mStateManager.startServices(); + } else { + mStateManager.stopServices(); + } + } + + // GENERAL SCREEN + else if (key.equals("pref_os_power_management")) { + if (prefs.getBoolean(key, false)) { + setMode("os"); + } + + } else if (key.equals("pref_internal_power_management")) { + if (prefs.getBoolean(key, false)) { + setMode("internal"); + } + + } else if (key.equals("pref_lockmode")) { + if (prefs.getBoolean(key, false)) { + setMode("lock"); + } + + } else if (key.equals("pref_runasroot")) { + if (prefs.getBoolean(key, false)) { + AsyncSuAvailable localSuAvailable = new AsyncSuAvailable(); + localSuAvailable.execute(); + } + + } else if (key.equals("pref_internalservice")) { + mStateManager.refreshInternalService(); + + } else if (key.equals("pref_disable_home")) { + if (prefs.getBoolean("pref_realfullscreen", false)) { + Toast.makeText(getActivity(), + getString(R.string.pref_realfullscreen_enabled), + Toast.LENGTH_SHORT).show(); + prefs.edit().putBoolean(key, false).commit(); + } + } + + // INTERNAL SERVICE SCREEN + else if (key.equals("pref_realhall")) { + if (prefs.getBoolean(key, false) + && prefs.getBoolean("pref_runasroot", false)) { + prefs.edit().putBoolean("pref_proximity", false).commit(); + } else { + prefs.edit().putBoolean(key, false).commit(); + } + mStateManager.restartServices(); + + } else if (key.equals("pref_proximity")) { + if (prefs.getBoolean(key, false)) { + prefs.edit().putBoolean("pref_realhall", false).commit(); + } + mStateManager.restartServices(); + } + + // DISPLAY SCREEN + else if (key.equals("pref_realfullscreen")) { + if (prefs.getBoolean("pref_disable_home", false)) { + Toast.makeText(getActivity(), + getString(R.string.pref_disable_enabled), + Toast.LENGTH_SHORT).show(); + prefs.edit().putBoolean(key, false).commit(); + } + } + + // WIDGET SCREEN + // if the default screen widget is being enabled/disabled the key + // will be pref_default_widget + else if (key.equals("pref_default_widget")) { + if (prefs.getBoolean(key, false) + && !mStateManager.hmAppWidgetManager + .doesWidgetExist("default")) { + mStateManager.registerWidget("default"); + } else if (!prefs.getBoolean(key, false) + && mStateManager.hmAppWidgetManager + .doesWidgetExist("default")) { + mStateManager.unregisterWidget("default"); + } + + } else + // if the media screen widget is being enabled/disabled the key will + // be pref_media_widget + if (key.equals("pref_media_widget")) { + if (prefs.getBoolean(key, false) + && !mStateManager.hmAppWidgetManager + .doesWidgetExist("media")) { + mStateManager.registerWidget("media"); + } else if (!prefs.getBoolean(key, false) + && mStateManager.hmAppWidgetManager + .doesWidgetExist("media")) { + mStateManager.unregisterWidget("media"); + } + + } + + // FEATURES SCREEN + else if (key.equals("pref_do_notifications")) { + doNotifications(getActivity(), prefs.getBoolean(key, false)); + + } else if (key.equals("pref_flash_controls")) { + if (prefs.getBoolean("pref_flash_controls_alternative", false)) { + Toast.makeText(getActivity(), + getString(R.string.alternative_torch_enabled), + Toast.LENGTH_SHORT).show(); + prefs.edit().putBoolean(key, false).commit(); + } else if (prefs.getBoolean(key, false)) { + try { + PackageManager packageManager = getActivity() + .getPackageManager(); + packageManager.getApplicationLogo("net.cactii.flash2"); + } catch (PackageManager.NameNotFoundException nfne) { + // if the app isn't installed, just refuse to set the + // preference + Toast.makeText(getActivity(), + getString(R.string.no_torch_app), + Toast.LENGTH_SHORT).show(); + prefs.edit().putBoolean(key, false).commit(); + } + } + + } else if (key.equals("pref_flash_controls_alternative")) { + if (prefs.getBoolean("pref_flash_controls", false)) { + Toast.makeText(getActivity(), + getString(R.string.default_torch_enabled), + Toast.LENGTH_SHORT).show(); + prefs.edit().putBoolean(key, false).commit(); + } else if (prefs.getBoolean(key, false)) { + if (mStateManager.getDeviceHasFlash()) { + prefs.edit().putBoolean(key, true).commit(); + } else { + // if the device does not have camera flash feature refuse + // to set the preference + Toast.makeText(getActivity(), getString(R.string.no_torch), + Toast.LENGTH_SHORT).show(); + prefs.edit().putBoolean(key, false).commit(); + } + } + + } + + // PHONE SCREEN + // preferences_phone + else if (key.equals("pref_phone_controls_tts_delay")) { + updatePhoneControlTtsDelay(prefs); + + } + + ; + + // Special case of restart + if (key.equals("pref_force_restart")) { + prefs.edit().putBoolean(key, false).commit(); + Intent mStartActivity = new Intent(getActivity() + .getApplicationContext(), Configuration.class); + mStartActivity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_NO_ANIMATION + | Intent.FLAG_ACTIVITY_CLEAR_TOP + | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + int mPendingIntentId = 123456; + PendingIntent mPendingIntent = PendingIntent.getActivity( + getActivity().getApplicationContext(), mPendingIntentId, + mStartActivity, PendingIntent.FLAG_CANCEL_CURRENT); + AlarmManager mgr = (AlarmManager) getActivity() + .getApplicationContext().getSystemService( + Context.ALARM_SERVICE); + mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, + mPendingIntent); + ((CoreApp) mStateManager.getContext()).restart(); + System.exit(0); + } else { + } + + // Rebuild dependency + // RealHall + enableRealHall(prefs); + // Phone Control + enablePhoneScreen(prefs); + // Power Mode + mStateManager.refreshInternalPowerManagement(); + mStateManager.refreshOsPowerManagement(); + mStateManager.refreshLockMode(); + } + + private void updatePhoneControlTtsDelay(SharedPreferences prefs) { + Preference preference = findPreference("pref_phone_controls_tts_delay"); + + if (preference != null && (preference instanceof ListPreference)) { + preference.setSummary(((ListPreference) preference).getEntry()); + } + } + + private void enablePhoneScreen(SharedPreferences prefs) { + boolean phoneControlState = prefs.getBoolean("pref_enabled", false) + && prefs.getBoolean("pref_runasroot", false); + boolean phoneControlConfig = prefs.getBoolean("pref_phone_controls", + false); + Preference phoneControl = findPreference("pref_phone_controls_user"); + + if (phoneControlConfig != phoneControlState && phoneControl != null) { + phoneControl.setEnabled(phoneControlState); + } + if (phoneControlConfig != (phoneControlState && prefs.getBoolean( + "pref_phone_controls_user", false))) { + prefs.edit().putBoolean("pref_phone_controls", !phoneControlConfig) + .commit(); + } + } + + private void setSystemApp(SharedPreferences prefs) { + if (mStateManager.getSystemApp()) { + if (findPreference("pref_internal_power_management") != null) { + findPreference("pref_internal_power_management").setEnabled( + true); + } + if (findPreference("pref_os_power_management") != null) { + findPreference("pref_os_power_management").setEnabled(true); + } + if (findPreference("pref_lockmode") != null) { + findPreference("pref_lockmode").setEnabled(true); + } + } else { + prefs.edit().putBoolean("pref_internal_power_management", false) + .commit(); + if (findPreference("pref_internal_power_management") != null) { + findPreference("pref_internal_power_management").setEnabled( + false); + } + if (findPreference("pref_os_power_management") != null) { + findPreference("pref_os_power_management").setEnabled(true); + } + if (findPreference("pref_lockmode") != null) { + findPreference("pref_lockmode").setEnabled(true); + } + } + } + + private void setMode(String mode) { + SharedPreferences prefs = getPreferenceManager().getSharedPreferences(); + if (mode == "internal" && mStateManager.getSystemApp()) { + prefs.edit().putBoolean("pref_os_power_management", false) + .putBoolean("pref_lockmode", false).commit(); + } else if (mode == "os") { + prefs.edit().putBoolean("pref_internal_power_management", false) + .putBoolean("pref_lockmode", false).commit(); + } else if (mode == "lock") { + prefs.edit().putBoolean("pref_internal_power_management", false) + .putBoolean("pref_os_power_management", false).commit(); + mStateManager.requestAdmin(); + } else { + prefs.edit().putBoolean("pref_internal_power_management", false) + .putBoolean("pref_os_power_management", false) + .putBoolean("pref_lockmode", false).commit(); + } + } + + private void enableRealHall(SharedPreferences prefs) { + if (prefs.getBoolean("pref_runasroot", false)) { + if (findPreference("pref_realhall") != null) { + findPreference("pref_realhall").setEnabled(true); + } + } else { + prefs.edit().putBoolean("pref_realhall", false); + if (findPreference("pref_realhall") != null) { + findPreference("pref_realhall").setEnabled(false); + } + } + + } + + private void Log_d(String tag, String message) { + if (mDebug) { + Log.d(tag, message); + } + } + + private SpannableString getTextDisabledFormatted(CharSequence text) { + // TODO: read default text color + int defaultTextColor = Color.BLACK; + + int alpha = Color.argb((int) (0.5f * 255), Color.red(defaultTextColor), + Color.green(defaultTextColor), Color.blue(defaultTextColor)); + + SpannableString spannableString = new SpannableString(text); + spannableString.setSpan(new ForegroundColorSpan(alpha), 0, + text.length(), 0); + + return spannableString; + } + + private void doNotifications(Activity act, boolean enable) { + + if (enable && !mStateManager.getNotificationSettingsOngoing() + && !mStateManager.getServiceRunning(NotificationService.class)) { + mStateManager.setNotificationSettingsOngoing(true); + Toast.makeText(act, act.getString(R.string.notif_please_check), + Toast.LENGTH_SHORT).show(); + act.startActivityForResult(new Intent( + "android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"), + CoreApp.NOTIFICATION_LISTENER_ON); + } else if (!enable && !mStateManager.getNotificationSettingsOngoing() + && mStateManager.getServiceRunning(NotificationService.class)) { + mStateManager.setNotificationSettingsOngoing(true); + Toast.makeText(act, act.getString(R.string.notif_please_uncheck), + Toast.LENGTH_SHORT).show(); + act.startActivityForResult(new Intent( + "android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"), + CoreApp.NOTIFICATION_LISTENER_OFF); + } + + } + + @Override + public boolean onPreferenceTreeClick(PreferenceScreen screen, + Preference pref) { + super.onPreferenceTreeClick(screen, pref); + + if (pref != null && pref instanceof PreferenceScreen) { + // make the back button on the action bar work (why doesn't it work + // by default???) + // FIXME this is another hack + // thanks be to + // https://stackoverflow.com/questions/16374820/action-bar-home-button-not-functional-with-nested-preferencescreen + + final PreferenceScreen ps = (PreferenceScreen) pref; + if (ps.getDialog() != null) { + ps.getDialog().getActionBar().setDisplayHomeAsUpEnabled(true); + + // carefully walk up two levels from the home button + View v = ps.getDialog().findViewById(android.R.id.home); + if (v != null) { + if (v.getParent() != null && v.getParent() instanceof View) { + v = (View) v.getParent(); + if (v.getParent() != null + && v.getParent() instanceof View) { + v = (View) v.getParent(); + + // found the view we want, make it so + v.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View view) { + ps.getDialog().dismiss(); + } + + }); + } + } + } + } + } + + return false; + } + + private class AsyncSuAvailable extends AsyncTask { @Override protected Boolean doInBackground(Boolean... params) { - return Shell.SU.available(); + return Shell.SU.available(); } - + @Override protected void onPostExecute(Boolean result) { - if(!result) - { - Toast.makeText(getActivity(), "Root access not granted - cannot enable root features!", Toast.LENGTH_SHORT).show(); - getPreferenceManager().getSharedPreferences().edit().putBoolean("pref_runasroot", false).commit(); + if (result) { + getPreferenceManager().getSharedPreferences().edit() + .putBoolean("pref_runasroot", true).commit(); + mStateManager.refreshRootApp(); + } else { + Toast.makeText( + getActivity(), + "Root access not granted - cannot enable root features!", + Toast.LENGTH_SHORT).show(); + getPreferenceManager().getSharedPreferences().edit() + .putBoolean("pref_runasroot", false).commit(); + mStateManager.refreshRootApp(); } } } diff --git a/src/org/durka/hallmonitor/SwipeTouchListener.java b/src/org/durka/hallmonitor/SwipeTouchListener.java index 1dafbd2..cd779c2 100644 --- a/src/org/durka/hallmonitor/SwipeTouchListener.java +++ b/src/org/durka/hallmonitor/SwipeTouchListener.java @@ -1,68 +1,367 @@ package org.durka.hallmonitor; -import android.content.ClipData; +import android.annotation.SuppressLint; import android.content.Context; +import android.content.Intent; +import android.support.v4.content.LocalBroadcastManager; +import android.support.v4.view.GestureDetectorCompat; +import android.support.v4.view.MotionEventCompat; import android.util.Log; -import android.view.GestureDetector; import android.view.GestureDetector.SimpleOnGestureListener; import android.view.MotionEvent; import android.view.View; -import android.view.View.DragShadowBuilder; import android.view.View.OnTouchListener; -import android.widget.ImageView; +//import android.graphics.Color; + +@SuppressLint("ClickableViewAccessibility") public class SwipeTouchListener implements OnTouchListener { - private final GestureDetector gestureDetector; - - public SwipeTouchListener(Context context) { - gestureDetector = new GestureDetector(context, new GestureListener()); - } - - public void onSwipeLeft() { - Functions.Actions.hangup_call(); - Log.d("Swipe", "Swipe Left, reject the call"); - } - - public void onSwipeRight() { - Functions.Actions.pickup_call(); - Log.d("Swipe", "Swipe Right, pickup the call"); - } - - public boolean onTouch(View v, MotionEvent event) { - return gestureDetector.onTouchEvent(event); - } - - private final class GestureListener extends SimpleOnGestureListener { - - private static final int SWIPE_DISTANCE_THRESHOLD = 350; - private static final int SWIPE_VELOCITY_THRESHOLD = 40; - - @Override - public boolean onDown(MotionEvent e) { - return true; - } - - @Override - public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { - float distanceX = e2.getX() - e1.getX(); - float distanceY = e2.getY() - e1.getY(); - ImageView hangup = (ImageView) Functions.defaultActivity.findViewById(R.id.hangup_button); - ImageView pickup = (ImageView) Functions.defaultActivity.findViewById(R.id.pickup_button); - - if (Math.abs(distanceX) > Math.abs(distanceY) && Math.abs(distanceX) > SWIPE_DISTANCE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) { - if (distanceX > 0) { - onSwipeRight(); - pickup.setTranslationX(e1.getX()); - Log.d("Swipe", "moving pickup icon"); - } else { - onSwipeLeft(); - hangup.setTranslationX(e2.getX()); - Log.d("Swipe", "moving hangup icon"); - } - return true; - } - return false; - } - } + private final String LOG_TAG = "Hall.Swipe"; + + private final CoreStateManager mStateManager; + + public enum ActionMode { + MODE_NOTHINGTRUE, MODE_CALL, MODE_ALARM, MODE_TORCH, MODE_CAMERA; + } + + private final GestureDetectorCompat gestureDetector; + private int _leftxDelta; + private int _rightxDelta; + private int _xDelta; + private final ActionMode actionMode; + private final Context ctx; + private int mActivePointerId = MotionEvent.INVALID_POINTER_ID; + + public SwipeTouchListener(Context context, ActionMode actionMode) { + this.ctx = context; + mStateManager = ((CoreApp) context.getApplicationContext()) + .getStateManager(); + this.actionMode = actionMode; + this.gestureDetector = new GestureDetectorCompat(this.ctx, + new SwipeGestureListener()); + } + + private void onSwipeLeft() { + Log.d(LOG_TAG, "Swipe Left, receive"); + + switch (this.actionMode) { + case MODE_CALL: + Log.d(LOG_TAG, "Swipe Left, reject the call"); + Intent hangUpCallIntent = new Intent(ctx, CoreService.class); + hangUpCallIntent.putExtra(CoreApp.CS_EXTRA_TASK, + CoreApp.CS_TASK_HANGUP_CALL); + mStateManager.sendToCoreService(hangUpCallIntent); + break; + case MODE_ALARM: + Log.d(LOG_TAG, "Swipe Left, dismiss... I am wake"); + Intent alarmDismiss = new Intent(ctx, CoreService.class); + alarmDismiss.putExtra(CoreApp.CS_EXTRA_TASK, + CoreApp.CS_TASK_DISMISS_ALARM); + mStateManager.sendToCoreService(alarmDismiss); + break; + case MODE_TORCH: + Log.d(LOG_TAG, "Swipe Left, toggle torch"); + Intent torchIntent = new Intent(ctx, CoreService.class); + torchIntent.putExtra(CoreApp.CS_EXTRA_TASK, + CoreApp.CS_TASK_TORCH_TOGGLE); + mStateManager.sendToCoreService(torchIntent); + break; + case MODE_CAMERA: + Log.d(LOG_TAG, "Swipe Left, toggle camera"); + Intent cameraIntent = new Intent(CoreApp.DA_ACTION_START_CAMERA); + LocalBroadcastManager mLocalBroadcastManager = LocalBroadcastManager + .getInstance(ctx); + mLocalBroadcastManager.sendBroadcastSync(cameraIntent); + break; + case MODE_NOTHINGTRUE: + break; + } + } + + private void onSwipeRight() { + Log.d(LOG_TAG, "Swipe Right, receive"); + + switch (this.actionMode) { + case MODE_CALL: + Log.d(LOG_TAG, "Swipe Right, pickup the call"); + Intent pickUpCallIntent = new Intent(ctx, CoreService.class); + pickUpCallIntent.putExtra(CoreApp.CS_EXTRA_TASK, + CoreApp.CS_TASK_PICKUP_CALL); + mStateManager.sendToCoreService(pickUpCallIntent); + break; + case MODE_ALARM: + Log.d(LOG_TAG, "Swipe Right, snooze alarm"); + Intent torchIntent = new Intent(ctx, CoreService.class); + torchIntent.putExtra(CoreApp.CS_EXTRA_TASK, + CoreApp.CS_TASK_SNOOZE_ALARM); + mStateManager.sendToCoreService(torchIntent); + break; + case MODE_TORCH: + Log.d(LOG_TAG, "Swipe Right, toggle torch only Left"); + break; + case MODE_CAMERA: + Log.d(LOG_TAG, "Swipe Right, toggle camera only Left"); + break; + case MODE_NOTHINGTRUE: + break; + } + } + + private void sendMotionEvent(final MotionEvent event, + final int pointerIndex, float x, float y) { + MotionEvent singleEvent = MotionEvent.obtain(event.getDownTime(), + event.getEventTime(), event.getActionMasked(), x, y, + event.getPressure(pointerIndex), event.getSize(pointerIndex), + event.getMetaState(), event.getXPrecision(), + event.getYPrecision(), event.getDeviceId(), + event.getEdgeFlags()); + this.gestureDetector.onTouchEvent(singleEvent); + singleEvent.recycle(); + } + + @Override + public boolean onTouch(View v, MotionEvent event) { + View leftImage = null; + View rightImage = null; + + boolean consumedEvent = false; + + switch (this.actionMode) { + case MODE_CALL: + leftImage = ((DefaultActivity) ctx) + .findViewById(R.id.pickup_button); + rightImage = ((DefaultActivity) ctx) + .findViewById(R.id.hangup_button); + break; + case MODE_ALARM: + leftImage = ((DefaultActivity) ctx).findViewById(R.id.snoozebutton); + rightImage = ((DefaultActivity) ctx) + .findViewById(R.id.dismissbutton); + break; + case MODE_TORCH: + leftImage = null; + rightImage = ((DefaultActivity) ctx).findViewById(R.id.torchbutton); + break; + case MODE_CAMERA: + leftImage = null; + rightImage = ((DefaultActivity) ctx) + .findViewById(R.id.camerabutton); + break; + case MODE_NOTHINGTRUE: + return consumedEvent = true; + } + + final int action = MotionEventCompat.getActionMasked(event); + + switch (action) { + case MotionEvent.ACTION_POINTER_DOWN: + case MotionEvent.ACTION_DOWN: { + // v.setBackgroundColor(Color.RED); + // v.invalidate(); + + if (mActivePointerId != MotionEvent.INVALID_POINTER_ID) { + break; + } + + final int pointerIndex = MotionEventCompat.getActionIndex(event); + final int pointerId = MotionEventCompat.getPointerId(event, + pointerIndex); + + // Get absolute coordinate of view + int pos[] = new int[2]; + v.getLocationOnScreen(pos); + + // v.setBackgroundColor(Color.MAGENTA); + // v.invalidate(); + + // // Only take pointer in our view + // if (MotionEventCompat.getX(event, pointerIndex) >= pos[0] + // && MotionEventCompat.getX(event, pointerIndex) <= (pos[0] + v + // .getWidth()) + // && MotionEventCompat.getY(event, pointerIndex) >= pos[1] + // && MotionEventCompat.getY(event, pointerIndex) <= (pos[1] + v + // .getHeight())) { + // mActivePointerId = pointerId; + // } else { + // mActivePointerId = MotionEvent.INVALID_POINTER_ID; + // // But follow all next touch + // consumedEvent = true; + // break; + // } + // v.setBackgroundColor(Color.YELLOW); + // v.invalidate(); + mActivePointerId = pointerId; + + // Disable sleep/lock timerTask + mStateManager.setBlackScreenTime(0); + + final int X = (int) MotionEventCompat.getX(event, pointerIndex); + // final int Y = (int)MotionEventCompat.getY(event, pointerIndex); + + // Move image + if (leftImage != null) { + _leftxDelta = (int) (X - leftImage.getTranslationX()); + } + if (rightImage != null) { + _rightxDelta = (int) (X - rightImage.getTranslationX()); + } + _xDelta = (X); + + // Forward to gestureDetector + this.sendMotionEvent(event, pointerIndex, + X * event.getXPrecision(), 0.0f); + + consumedEvent = true; + break; + } + case MotionEvent.ACTION_MOVE: { + int pointerIndex = MotionEventCompat.findPointerIndex(event, + mActivePointerId); + + if (pointerIndex == -1) { + break; + } + + mStateManager.setBlackScreenTime(0); + + // v.setBackgroundColor(Color.GREEN); + // v.invalidate(); + + // Get absolute coordinate from event + int pos[] = new int[2]; + v.getLocationOnScreen(pos); + final int X = (int) MotionEventCompat.getX(event, pointerIndex) + + pos[0]; + // final int Y = (int)MotionEventCompat.getY(event, pointerIndex) + + // pos[1]; + + // Move image + if (X < _xDelta) { + if (leftImage != null) { + leftImage.setTranslationX(0); + } + if (rightImage != null) { + rightImage.setTranslationX(X - _rightxDelta); + } + } else if (X > _xDelta) { + if (rightImage != null) { + rightImage.setTranslationX(0); + } + if (leftImage != null) { + leftImage.setTranslationX(X - _leftxDelta); + } + } + + // Forward to gestureDetector + this.sendMotionEvent(event, pointerIndex, + X * event.getXPrecision(), 0.0f); + + consumedEvent = true; + break; + } + case MotionEvent.ACTION_POINTER_UP: + case MotionEvent.ACTION_UP: { + // v.setBackgroundColor(Color.CYAN); + // v.invalidate(); + + final int pointerIndex = MotionEventCompat.getActionIndex(event); + final int pointerId = MotionEventCompat.getPointerId(event, + pointerIndex); + + if (pointerId != mActivePointerId) { + break; + } + + // Get absolute coordinate from event + int pos[] = new int[2]; + v.getLocationOnScreen(pos); + final int X = (int) MotionEventCompat.getX(event, pointerIndex) + + pos[0]; + // final int Y = (int)MotionEventCompat.getY(event, pointerIndex) + + // pos[1]; + + // Reset image + if (leftImage != null) { + leftImage.setTranslationX(0); + } + if (rightImage != null) { + rightImage.setTranslationX(0); + } + + // Forward to gestureDetector + this.sendMotionEvent(event, pointerIndex, + X * event.getXPrecision(), 0.0f); + + consumedEvent = true; + + // Enable sleep/lock timerTask + Intent mIntent = new Intent(ctx, CoreService.class); + mIntent.putExtra(CoreApp.CS_EXTRA_TASK, + CoreApp.CS_TASK_AUTO_BLACKSCREEN); + mStateManager.sendToCoreService(mIntent); + + // End our touch event + mActivePointerId = MotionEvent.INVALID_POINTER_ID; + break; + } + case MotionEvent.ACTION_CANCEL: { + // v.setBackgroundColor(Color.WHITE); + // v.invalidate(); + + final int pointerIndex = MotionEventCompat.getActionIndex(event); + final int pointerId = MotionEventCompat.getPointerId(event, + pointerIndex); + + if (pointerId != mActivePointerId) { + break; + } + + consumedEvent = true; + + // Enable sleep/lock timerTask + Intent mIntent = new Intent(ctx, CoreService.class); + mIntent.putExtra(CoreApp.CS_EXTRA_TASK, + CoreApp.CS_TASK_AUTO_BLACKSCREEN); + mStateManager.sendToCoreService(mIntent); + + mActivePointerId = MotionEvent.INVALID_POINTER_ID; + break; + } + } + return consumedEvent; + } + + private final class SwipeGestureListener extends SimpleOnGestureListener { + + private static final int SWIPE_DISTANCE_THRESHOLD = 200; + private static final int SWIPE_VELOCITY_THRESHOLD = 40; + + @Override + public boolean onDown(MotionEvent e) { + return true; + } + + @Override + public boolean onScroll(MotionEvent e1, MotionEvent e2, + float distanceX, float distanceY) { + return true; + } + + @Override + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, + float velocityY) { + float distanceX = e2.getRawX() - e1.getRawX(); + + if (Math.abs(distanceX) > SWIPE_DISTANCE_THRESHOLD + && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) { + if (distanceX > 0) { + onSwipeRight(); + } else { + onSwipeLeft(); + } + } + return true; + } + } } \ No newline at end of file diff --git a/src/org/durka/hallmonitor/ViewCoverHallService.java b/src/org/durka/hallmonitor/ViewCoverHallService.java index 6fa7976..c86774b 100644 --- a/src/org/durka/hallmonitor/ViewCoverHallService.java +++ b/src/org/durka/hallmonitor/ViewCoverHallService.java @@ -14,110 +14,82 @@ */ package org.durka.hallmonitor; -import java.lang.Thread; - import android.app.Service; -import android.appwidget.AppWidgetManager; import android.content.Intent; -import android.content.IntentFilter; -import android.content.SharedPreferences; import android.os.Build; import android.os.IBinder; -import android.preference.PreferenceManager; +import android.support.v4.content.LocalBroadcastManager; import android.util.Log; import com.manusfreedom.android.Events; import com.manusfreedom.android.Events.InputDevice; -import eu.chainfire.libsuperuser.Shell; - public class ViewCoverHallService extends Service implements Runnable { - - private HeadsetReceiver mHeadset; - private Thread getevent; - private Boolean serviceStarted; + private final String LOG_TAG = "Hall.VCHS"; + + private Thread getevent; + private Boolean serviceStarted; + + private static final String DEV_SERRANO_LTE_CM10 = "serranolte"; // GT-I9195 + // CM10.x + private static final String DEV_SERRANO_LTE_CM11 = "serranoltexx"; // GT-I9195 + // CM11.x - private static final String DEV_SERRANO_LTE_CM10 = "serranolte"; // GT-I9195 CM10.x - private static final String DEV_SERRANO_LTE_CM11 = "serranoltexx"; // GT-I9195 CM11.x + private CoreStateManager mStateManager; + private LocalBroadcastManager mLocalBroadcastManager; + + @Override + public void onCreate() { + Log.d(LOG_TAG + ".oC", "Core service creating"); + + mStateManager = ((CoreApp) getApplicationContext()).getStateManager(); + mLocalBroadcastManager = LocalBroadcastManager.getInstance(this); + } @Override public int onStartCommand(Intent intent, int flags, int startId) { - Log.d("VCHS.onStartCommand", "View cover Hall service started"); - - //We don't want to do this - almost by definition the cover can't be closed, and we don't actually want to do any open cover functionality - //until the cover is closed and then opened again - /*if (Functions.Is.cover_closed(this)) { - Functions.Actions.close_cover(this); - } else { - Functions.Actions.open_cover(this); - } */ - - mHeadset = new HeadsetReceiver(); - IntentFilter intfil = new IntentFilter(); - intfil.addAction("android.intent.action.HEADSET_PLUG"); - registerReceiver(mHeadset, intfil); - - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - if (prefs.getBoolean("pref_default_widget", false) - && !Functions.hmAppWidgetManager.doesWidgetExist("default")) { - - int id = prefs.getInt("default_widget_id", -1); - if (id != -1) { - Log.d("VCHS-oSC", "creating default widget with id=" + id); - - Intent data = new Intent(); - data.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id); - - Functions.hmAppWidgetManager.currentWidgetType = "default"; - Functions.hmAppWidgetManager.createWidget(data, this); - } - } - if (prefs.getBoolean("pref_default_widget", false) - && !Functions.hmAppWidgetManager.doesWidgetExist("media")) { - - int id = prefs.getInt("media_widget_id", -1); - if (id != -1) { - Log.d("VCHS-oSC", "creating media widget with id=" + id); - - Intent data = new Intent(); - data.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id); - - Functions.hmAppWidgetManager.currentWidgetType = "media"; - Functions.hmAppWidgetManager.createWidget(data, this); - } - } + Log.d(LOG_TAG + ".oSC", "View cover Hall service started"); + serviceStarted = true; - + getevent = new Thread(this); getevent.start(); return START_STICKY; } - + @Override public void run() { - Log.d("VCHS-oSC", "Request root"); - Shell.SU.available(); + if (!mStateManager.getRootApp()) { + Log.e(LOG_TAG + ".r", "Required root to use Real Hall service"); + + return; + } String neededDevice = "gpio-keys"; - if(Build.DEVICE.equals(DEV_SERRANO_LTE_CM10) || Build.DEVICE.equals(DEV_SERRANO_LTE_CM11)){ + if (Build.DEVICE.equals(DEV_SERRANO_LTE_CM10) + || Build.DEVICE.equals(DEV_SERRANO_LTE_CM11)) { neededDevice = "sec_keys"; } Events events = new Events(); - + events.AddAllDevices(); String neededDevicePath = ""; - Log.e("VCHS-oSC", "Number of device found:" + events.m_Devs.size()); + Log.d(LOG_TAG + ".r", "Number of device found:" + events.m_Devs.size()); - Log.d("VCHS-oSC", "Scan device"); - for (InputDevice idev:events.m_Devs) { - if(!idev.getOpen()) - idev.Open(true); - if(idev.getOpen()) { - Log.d("VCHS-oSC", " Open: " + idev.getPath() + " / Name: " + idev.getName() + " / Version: " + idev.getVersion() + " / Location: " + idev.getLocation() + " / IdStr: " + idev.getIdStr() + " / Result: " + idev.getOpen()); - if(idev.getName().equals(neededDevice)){ - Log.d("VCHS-oSC", "Device " + neededDevice + " found"); + Log.d(LOG_TAG + ".r", "Scan device"); + for (InputDevice idev : events.m_Devs) { + if (!idev.getOpen()) { + idev.Open(true, mStateManager.getRootApp()); + } + if (idev.getOpen()) { + Log.d(LOG_TAG + ".r", " Open: " + idev.getPath() + " / Name: " + + idev.getName() + " / Version: " + idev.getVersion() + + " / Location: " + idev.getLocation() + " / IdStr: " + + idev.getIdStr() + " / Result: " + idev.getOpen()); + if (idev.getName().equals(neededDevice)) { + Log.d(LOG_TAG + ".r", "Device " + neededDevice + " found"); neededDevicePath = idev.getPath(); break; } @@ -126,59 +98,78 @@ public void run() { events.Release(); events = null; System.gc(); - + events = new Events(); events.AddDevice(neededDevicePath); - Log.e("VCHS-oSC", "Number of device found:" + events.m_Devs.size()); - + Log.e(LOG_TAG + ".r", "Number of device found:" + events.m_Devs.size()); + InputDevice currentInputDevice = null; - for (InputDevice idev:events.m_Devs) { - if(!idev.getOpen()) - idev.Open(true); + for (InputDevice idev : events.m_Devs) { + if (!idev.getOpen()) { + idev.Open(true, mStateManager.getRootApp()); + } currentInputDevice = idev; - Log.d("VCHS-oSC", "Open: " + currentInputDevice.getPath() + " / Name: " + currentInputDevice.getName() + " / Version: " + currentInputDevice.getVersion() + " / Location: " + currentInputDevice.getLocation() + " / IdStr: " + currentInputDevice.getIdStr() + " / Result: " + currentInputDevice.getOpen()); + Log.d(LOG_TAG + ".r", "Open: " + currentInputDevice.getPath() + + " / Name: " + currentInputDevice.getName() + + " / Version: " + currentInputDevice.getVersion() + + " / Location: " + currentInputDevice.getLocation() + + " / IdStr: " + currentInputDevice.getIdStr() + + " / Result: " + currentInputDevice.getOpen()); } - - if(currentInputDevice == null) - { - Log.d("VCHS-oSC", "No device"); + + if (currentInputDevice == null) { + Log.d(LOG_TAG + ".r", "No device"); return; - } + } - Log.d("VCHS-oSC", "Start read command"); + Log.d(LOG_TAG + ".r", "Start read command"); while (serviceStarted) { - if(currentInputDevice.getOpen() && (0 == currentInputDevice.getPollingEvent())) { - Log.d("VCHS-oSC", "Reading command: " + currentInputDevice.getSuccessfulPollingType() + "/" + currentInputDevice.getSuccessfulPollingCode() + "/" + currentInputDevice.getSuccessfulPollingValue()); - if(currentInputDevice.getSuccessfulPollingCode() == 21 && currentInputDevice.getSuccessfulPollingValue() == 0){ - Log.i("VCHS-oSC", "Cover closed"); - Functions.Actions.close_cover(this); - } - else if(currentInputDevice.getSuccessfulPollingCode() == 21 && currentInputDevice.getSuccessfulPollingValue() == 1){ - Log.i("VCHS-oSC", "Cover open"); - Functions.Actions.open_cover(this); + if (currentInputDevice.getOpen() + && (0 == currentInputDevice.getPollingEvent())) { + Log.d(LOG_TAG + ".r", + "Reading command: " + + currentInputDevice.getSuccessfulPollingType() + + "/" + + currentInputDevice.getSuccessfulPollingCode() + + "/" + + currentInputDevice + .getSuccessfulPollingValue()); + if (currentInputDevice.getSuccessfulPollingCode() == 21 + && currentInputDevice.getSuccessfulPollingValue() == 0) { + Log.i(LOG_TAG + ".r", "Cover closed"); + Intent intent = new Intent(mStateManager.getActionCover()); + intent.putExtra(CoreReceiver.EXTRA_LID_STATE, + CoreReceiver.LID_CLOSED); + this.mLocalBroadcastManager.sendBroadcastSync(intent); + } else if (currentInputDevice.getSuccessfulPollingCode() == 21 + && currentInputDevice.getSuccessfulPollingValue() == 1) { + Log.i(LOG_TAG + ".r", "Cover open"); + Intent intent = new Intent(mStateManager.getActionCover()); + intent.putExtra(CoreReceiver.EXTRA_LID_STATE, + CoreReceiver.LID_OPEN); + this.mLocalBroadcastManager.sendBroadcastSync(intent); } } } - Log.d("VCHS-oSC", "Stop read command"); + Log.d(LOG_TAG + ".r", "Stop read command"); events.Release(); events = null; - Log.d("VCHS-oSC", "Memory cleaned"); + Log.d(LOG_TAG + ".r", "Memory cleaned"); System.gc(); } - + @Override public IBinder onBind(Intent intent) { return null; } - + @Override public void onDestroy() { - Log.d("VCHS.onStartCommand", "View cover Hall service stopped"); + Log.d(LOG_TAG + ".oD", "View cover Hall service stopped"); serviceStarted = false; - unregisterReceiver(mHeadset); System.gc(); - + super.onDestroy(); } diff --git a/src/org/durka/hallmonitor/ViewCoverProximityService.java b/src/org/durka/hallmonitor/ViewCoverProximityService.java index 251cf97..4c8bb6a 100644 --- a/src/org/durka/hallmonitor/ViewCoverProximityService.java +++ b/src/org/durka/hallmonitor/ViewCoverProximityService.java @@ -18,125 +18,130 @@ import java.util.TimerTask; import android.app.Service; -import android.appwidget.AppWidgetManager; import android.content.Intent; -import android.content.IntentFilter; -import android.content.SharedPreferences; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.os.IBinder; -import android.preference.PreferenceManager; +import android.support.v4.content.LocalBroadcastManager; import android.util.Log; -public class ViewCoverProximityService extends Service implements SensorEventListener { - - private SensorManager mSensorManager; - private HeadsetReceiver mHeadset; - +public class ViewCoverProximityService extends Service implements + SensorEventListener { + private final String LOG_TAG = "Hall.VCPS"; + + private CoreStateManager mStateManager; + private LocalBroadcastManager mLocalBroadcastManager; + + private SensorManager mSensorManager; + + @Override + public void onCreate() { + Log.d(LOG_TAG + ".oC", "Core service creating"); + + mStateManager = ((CoreApp) getApplicationContext()).getStateManager(); + mLocalBroadcastManager = LocalBroadcastManager.getInstance(this); + } + @Override public int onStartCommand(Intent intent, int flags, int startId) { - Log.d("VCPS.onStartCommand", "View cover Proximity service started"); + Log.d(LOG_TAG + ".oSC", "View cover Proximity service started"); - //We don't want to do this - almost by defninition the cover can't be closed, and we don't actually want to do any open cover functionality - //until the cover is closed and then opened again - /*if (Functions.Is.cover_closed(this)) { - Functions.Actions.close_cover(this); - } else { - Functions.Actions.open_cover(this); - } */ - mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE); - - mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY), SensorManager.SENSOR_DELAY_NORMAL); - - mHeadset = new HeadsetReceiver(); - IntentFilter intfil = new IntentFilter(); - intfil.addAction("android.intent.action.HEADSET_PLUG"); - registerReceiver(mHeadset, intfil); - - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - if (prefs.getBoolean("pref_default_widget", false) - && !Functions.hmAppWidgetManager.doesWidgetExist("default")) { - - int id = prefs.getInt("default_widget_id", -1); - if (id != -1) { - Log.d("VCPS-oSC", "creating default widget with id=" + id); - - Intent data = new Intent(); - data.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id); - - Functions.hmAppWidgetManager.currentWidgetType = "default"; - Functions.hmAppWidgetManager.createWidget(data, this); - } - } - if (prefs.getBoolean("pref_default_widget", false) - && !Functions.hmAppWidgetManager.doesWidgetExist("media")) { - - int id = prefs.getInt("media_widget_id", -1); - if (id != -1) { - Log.d("VCPS-oSC", "creating media widget with id=" + id); - - Intent data = new Intent(); - data.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id); - - Functions.hmAppWidgetManager.currentWidgetType = "media"; - Functions.hmAppWidgetManager.createWidget(data, this); - } - } - + + mSensorManager.registerListener(this, + mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY), + SensorManager.SENSOR_DELAY_NORMAL); return START_STICKY; } - + @Override public IBinder onBind(Intent intent) { return null; } - + @Override public void onDestroy() { - Log.d("VCPS.onStartCommand", "View cover Proximity service stopped"); - - //unregisterReceiver(receiver); + Log.d(LOG_TAG + ".oD", "View cover Proximity service stopped"); + mSensorManager.unregisterListener(this); - - unregisterReceiver(mHeadset); + super.onDestroy(); } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { // I don't care - Log.d("VCPS.onAccuracyChanged", "OnAccuracyChanged: Sensor=" + sensor.getName() + ", accuracy=" + accuracy); + Log.d(LOG_TAG + ".oAC", "Sensor=" + sensor.getName() + ", accuracy=" + + accuracy); } @Override public void onSensorChanged(SensorEvent event) { - - if (event.sensor.getType() == Sensor.TYPE_PROXIMITY) { - Log.d("VCPS.onSensorChanged", "Proximity sensor changed, value=" + event.values[0]); - Functions.Events.proximity(this, event.values[0]); - - //improve reliability by refiring the event 200ms afterwards + + if (event.sensor.getType() == Sensor.TYPE_PROXIMITY) { + Log.d(LOG_TAG + ".onSC", "Proximity sensor changed, value=" + + event.values[0]); + proximity(event.values[0]); + + // improve reliability by refiring the event 200ms afterwards final float val = event.values[0]; Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override - public void run() { - Functions.Events.proximity(getApplicationContext(), val); + public void run() { + proximity(val); } }, 200); - + timer.schedule(new TimerTask() { @Override - public void run() { - Functions.Events.proximity(getApplicationContext(), val); + public void run() { + proximity(val); } }, 500); - + } } + /** + * Receives the value of the proximity sensor and reacts accordingly to + * update the cover state. + * + * @param ctx + * Application context. + * @param value + * Value of the proximity sensor. + */ + private void proximity(float value) { + + Log.d(LOG_TAG + ".proximity", + "Proximity method called with value: " + value + + " ,whilst cover_closed is: " + + mStateManager.getCoverClosed()); + + if (value > 0) { + if (!mStateManager.getCoverClosed(true)) { + // proximity false (>0) and cover open - take open_cover + // action + Intent intent = new Intent(mStateManager.getActionCover()); + intent.putExtra(CoreReceiver.EXTRA_LID_STATE, + CoreReceiver.LID_OPEN); + this.mLocalBroadcastManager.sendBroadcastSync(intent); + } + } else { + if (mStateManager.getCoverClosed(true)) { + // proximity true (<=0) and cover closed - take + // close_cover action + Intent intent = new Intent(mStateManager.getActionCover()); + intent.putExtra(CoreReceiver.EXTRA_LID_STATE, + CoreReceiver.LID_CLOSED); + this.mLocalBroadcastManager.sendBroadcastSync(intent); + } + } + // Log.d(LOG_TAG + ".Evt.proximity", + // String.format("cover_closed = %b", cover_closed)); + } }