diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index 417982ba..5c222929 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -1,7 +1,9 @@ - + @@ -63,6 +65,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -72,6 +116,7 @@ + diff --git a/android/src/ca/openprivacy/cwtch/ui/CwtchActivity.java b/android/src/ca/openprivacy/cwtch/ui/CwtchActivity.java index 4623ae15..5936c34b 100644 --- a/android/src/ca/openprivacy/cwtch/ui/CwtchActivity.java +++ b/android/src/ca/openprivacy/cwtch/ui/CwtchActivity.java @@ -4,8 +4,10 @@ import android.app.Notification; import android.app.NotificationManager; import android.app.NotificationChannel; import android.content.Context; +import android.content.Intent; import android.util.Log; - +import android.os.Bundle; +import android.content.ComponentName; import static android.app.Notification.DEFAULT_LIGHTS; import static android.app.Notification.DEFAULT_SOUND; @@ -18,19 +20,6 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.os.Build.VERSION.SDK_INT; import static android.app.Notification.CATEGORY_SERVICE; - -/*import static android.support.v4.app.NotificationCompat.CATEGORY_MESSAGE; -import static android.support.v4.app.NotificationCompat.CATEGORY_SERVICE; -import static android.support.v4.app.NotificationCompat.CATEGORY_SOCIAL; -import static android.support.v4.app.NotificationCompat.PRIORITY_LOW; -import static android.support.v4.app.NotificationCompat.PRIORITY_MIN; -import static android.support.v4.app.NotificationCompat.PRIORITY_DEFAULT; -import static android.support.v4.app.NotificationCompat.VISIBILITY_SECRET; -import static android.support.v4.content.ContextCompat.getColor;*/ - - - - public class CwtchActivity extends org.qtproject.qt5.android.bindings.QtActivity { private static NotificationManager m_notificationManager; @@ -50,11 +39,24 @@ public class CwtchActivity extends org.qtproject.qt5.android.bindings.QtActivity private static String CONTENT_NOTIFICATION_ID_NAME = "content"; - public CwtchActivity() - { + public CwtchActivity() { m_instance = this; } + // https://github.com/bbernhard/qtandroidservices_example/blob/master/source/java/MyCustomAppActivity.java + @Override + public void onCreate(Bundle bundle) { + super.onCreate(bundle); + Log.i("CwtchActivity", "Starting service!"); + Intent serviceIntent = new Intent(this, ca.openprivacy.cwtch.ui.CwtchService.class); + ComponentName ret = startService(serviceIntent); + if (ret == null) { + Log.i("CwtchActivity", "Started Service: FAILED with null"); + } else { + Log.i("CwtchActivity", "Started Service: " + ret.flattenToString()); + } + } + public static void notify(String s) { if (m_notificationManager == null) { diff --git a/android/src/ca/openprivacy/cwtch/ui/CwtchService.java b/android/src/ca/openprivacy/cwtch/ui/CwtchService.java new file mode 100644 index 00000000..13601b45 --- /dev/null +++ b/android/src/ca/openprivacy/cwtch/ui/CwtchService.java @@ -0,0 +1,15 @@ +package ca.openprivacy.cwtch.ui; + + +import android.app.IntentService; +import android.content.Intent; +import android.util.Log; +import android.content.Context; +import android.content.Intent; +import org.qtproject.qt5.android.bindings.QtService; + +// https://github.com/bbernhard/qtandroidservices_example +public class CwtchService extends QtService { + +} + diff --git a/go/characters/torstatuspoller.go b/go/characters/torstatuspoller.go index 135f441d..9fe7950c 100644 --- a/go/characters/torstatuspoller.go +++ b/go/characters/torstatuspoller.go @@ -6,6 +6,9 @@ import ( ) func TorStatusPoller(setTorStatus func(int, string), acn connectivity.ACN) { + if acn == nil { + return + } for { time.Sleep(time.Second) diff --git a/go/gothings/androidCwtchActivity.go b/go/gothings/android/CwtchActivity.go similarity index 77% rename from go/gothings/androidCwtchActivity.go rename to go/gothings/android/CwtchActivity.go index 72e41fa8..e0ae4050 100644 --- a/go/gothings/androidCwtchActivity.go +++ b/go/gothings/android/CwtchActivity.go @@ -1,11 +1,11 @@ -package gothings +package android import ( "github.com/therecipe/qt/androidextras" "github.com/therecipe/qt/core" ) -type AndroidCwtchActivity struct { +type CwtchActivity struct { core.QObject _ func() `constructor:"init"` @@ -15,13 +15,13 @@ type AndroidCwtchActivity struct { _ func(string) `slot:"updateAndroidNotification"` } -func (c *AndroidCwtchActivity) init() { +func (c *CwtchActivity) init() { c.createOngoingNotification() c.ConnectNotificationChanged(c.updateAndroidNotification) } -func (c *AndroidCwtchActivity) updateAndroidNotification(n string) { +func (c *CwtchActivity) updateAndroidNotification(n string) { var err = androidextras.QAndroidJniObject_CallStaticMethodVoid2Caught( "ca/openprivacy/cwtch/ui/CwtchActivity", @@ -35,7 +35,7 @@ func (c *AndroidCwtchActivity) updateAndroidNotification(n string) { } } -func (c *AndroidCwtchActivity) createOngoingNotification() { +func (c *CwtchActivity) createOngoingNotification() { var err = androidextras.QAndroidJniObject_CallStaticMethodVoid2Caught( "ca/openprivacy/cwtch/ui/CwtchActivity", diff --git a/go/the/globals.go b/go/the/globals.go index 2d75bd7c..a4239d08 100644 --- a/go/the/globals.go +++ b/go/the/globals.go @@ -8,11 +8,13 @@ import ( ) var CwtchApp app.Application +var CwtchService app.ApplicationService var EventBus event.Manager var AppBus event.Manager var ACN connectivity.ACN var Peer libPeer.CwtchPeer var CwtchDir string +var IPCBridge event.IPCBridge type AckId struct { ID string diff --git a/main.go b/main.go index 36009b73..9ee3c276 100644 --- a/main.go +++ b/main.go @@ -2,12 +2,13 @@ package main import ( libapp "cwtch.im/cwtch/app" + "cwtch.im/cwtch/event/bridge" "cwtch.im/ui/go/characters" "cwtch.im/ui/go/gobjects" "cwtch.im/ui/go/gothings" + "cwtch.im/ui/go/gothings/android" "cwtch.im/ui/go/the" "flag" - "fmt" "git.openprivacy.ca/openprivacy/libricochet-go/connectivity" "git.openprivacy.ca/openprivacy/libricochet-go/log" "github.com/therecipe/qt/core" @@ -35,8 +36,10 @@ func init() { } func main() { + log.Infoln("ui main()\n") flagDebug := flag.Bool("debug", false, "turn on extra logging. WARNING: THIS MAY EXPOSE PRIVATE INFORMATION IN CONSOLE OUTPUT!") flagLocal := flag.Bool("local", false, "load user interface from the local folder \"qml\" instead of the built-in UI") + flagService := flag.Bool("service", false, "indicate this process should run as an android service") flag.Parse() if *flagDebug { @@ -45,6 +48,60 @@ func main() { log.SetLevel(log.LevelInfo) } + // TESTING + log.SetLevel(log.LevelDebug) + log.ExcludeFromPattern("connection/connection") + log.ExcludeFromPattern("outbound/3dhauthchannel") + log.ExcludeFromPattern("event/eventmanager") + + if os.Getenv("CWTCH_FOLDER") != "" { + the.CwtchDir = os.Getenv("CWTCH_FOLDER") + } else if runtime.GOOS == "android" { + the.CwtchDir = path.Join(androidBaseDir, "files") + } else { + usr, err := user.Current() + if err != nil { + log.Errorf("\nerror: could not load current user: %v\n", err) + os.Exit(1) + } + the.CwtchDir = path.Join(usr.HomeDir, ".cwtch") + } + the.ACN = nil + the.Peer = nil + the.IPCBridge = nil + the.CwtchApp = nil + the.CwtchService = nil + os.MkdirAll(the.CwtchDir, 0700) + + if *flagService { + mainService() + + } else { + mainUi(*flagLocal) + } + + if the.ACN != nil { + the.ACN.Close() + } +} + +func mainService() { + log.Infoln("I am the service") + log.Infoln("Starting a cwtch app...") + go loadNetworkingAndFiles(nil, true) + + //app := androidextras.NewQAndroidService(len(os.Args), os.Args) + app := gui.NewQGuiApplication(len(os.Args), os.Args) + log.Infoln("Cwtch Service starting app.Exec") + app.Exec() + +} + +func mainUi(flagLocal bool) { + log.Infoln("I am the application") + + app := gui.NewQGuiApplication(len(os.Args), os.Args) + // our globals gcd := gothings.NewGrandCentralDispatcher(nil) gcd.SetOs(runtime.GOOS) @@ -64,13 +121,12 @@ func main() { // this is to load local qml files quickly when developing var qmlSource *core.QUrl - if *flagLocal { + if flagLocal { qmlSource = core.QUrl_FromLocalFile("./qml/main.qml") } else { qmlSource = core.NewQUrl3("qrc:/qml/main.qml", 0) } - app := gui.NewQGuiApplication(len(os.Args), os.Args) app.SetWindowIcon(gui.NewQIcon5(":/qml/images/cwtch-icon.png")) // load english first so it becomes the default in case we don't have a .ts for the user's locale, or if it contains unfinished strings @@ -111,33 +167,19 @@ func main() { } engine.RootContext().SetContextProperty("gcd", gcd) - var androidCwtchActivity = gothings.NewAndroidCwtchActivity(nil) + var androidCwtchActivity = android.NewCwtchActivity(nil) engine.RootContext().SetContextProperty("androidCwtchActivity", androidCwtchActivity) engine.Load(qmlSource) - the.ACN = nil - go loadNetworkingAndFiles(gcd) + + go loadNetworkingAndFiles(gcd, false) + + log.Infoln("Cwtch App starting app.Exec") app.Exec() - if the.ACN != nil { - the.ACN.Close() - } } -func loadNetworkingAndFiles(gcd *gothings.GrandCentralDispatcher) { - if os.Getenv("CWTCH_FOLDER") != "" { - the.CwtchDir = os.Getenv("CWTCH_FOLDER") - } else if runtime.GOOS == "android" { - the.CwtchDir = path.Join(androidBaseDir, "files") - } else { - usr, err := user.Current() - if err != nil { - fmt.Printf("\nerror: could not load current user: %v\n", err) - os.Exit(1) - } - the.CwtchDir = path.Join(usr.HomeDir, ".cwtch") - } - +func loadACN() { torpath := "tor" if runtime.GOOS == "android" { torpath = path.Join(androidBaseDir, "lib/libtor.so") @@ -163,12 +205,39 @@ func loadNetworkingAndFiles(gcd *gothings.GrandCentralDispatcher) { log.Errorf("Could not start Tor: %v", err) os.Exit(1) } - - the.Peer = nil - os.MkdirAll(the.CwtchDir, 0700) - - the.CwtchApp = libapp.NewApp(the.ACN, the.CwtchDir) - the.AppBus = the.CwtchApp.GetPrimaryBus() - go characters.AppEventListener(gcd) - the.CwtchApp.LoadProfiles("be gay do crime") +} + +func loadNetworkingAndFiles(gcd *gothings.GrandCentralDispatcher, service bool) { + if runtime.GOOS == "android" { + clientIn := path.Join(the.CwtchDir, "clientIn") + serviceIn := path.Join(the.CwtchDir, "serviceIn") + if service { + loadACN() + serviceBridge, err := bridge.NewPipeBridgeService(serviceIn, clientIn) + if err != nil { + log.Errorf("Could not create service bridge: %v\n", err) + os.Exit(1) + } + log.Infoln("Creating New App Service") + the.CwtchService = libapp.NewAppService(the.ACN, the.CwtchDir, serviceBridge) + } else { + clientBridge, err := bridge.NewPipeBridgeClient(clientIn, serviceIn) + if err != nil { + log.Errorf("Could not create client bridge: %v\n", err) + os.Exit(1) + } + log.Infoln("Creating New App Client") + the.CwtchApp = libapp.NewAppClient(the.CwtchDir, clientBridge) + } + } else { + loadACN() + log.Infoln("Creating New App") + the.CwtchApp = libapp.NewApp(the.ACN, the.CwtchDir) + } + + if !service { + the.AppBus = the.CwtchApp.GetPrimaryBus() + go characters.AppEventListener(gcd) + the.CwtchApp.LoadProfiles("be gay do crime") + } }