From d5c098ca742775e0f10b2110ea4396411b0764a8 Mon Sep 17 00:00:00 2001 From: hhd <271357901@qq.com> Date: Sat, 5 Nov 2022 18:22:16 +0800 Subject: [PATCH] support android --- .../main/java/cn/openp2p/OpenP2PService.kt | 90 +++++++++++++++---- .../java/cn/openp2p/ui/login/LoginActivity.kt | 87 +++++++++--------- app/app/src/main/res/drawable/icon.xml | 4 + core/install.go | 2 +- core/nat.go | 5 ++ core/openp2p.go | 17 ++-- core/p2pnetwork.go | 2 +- go.mod | 1 + 8 files changed, 141 insertions(+), 67 deletions(-) create mode 100644 app/app/src/main/res/drawable/icon.xml diff --git a/app/app/src/main/java/cn/openp2p/OpenP2PService.kt b/app/app/src/main/java/cn/openp2p/OpenP2PService.kt index d3f8410..d2542dd 100644 --- a/app/app/src/main/java/cn/openp2p/OpenP2PService.kt +++ b/app/app/src/main/java/cn/openp2p/OpenP2PService.kt @@ -1,17 +1,22 @@ package cn.openp2p -import android.app.Service +import android.app.* +import android.content.Context import android.content.Intent -import android.net.VpnService +import android.graphics.Color import android.os.Binder +import android.os.Build import android.os.IBinder -import openp2p.Openp2p import android.util.Log +import androidx.annotation.RequiresApi +import androidx.core.app.NotificationCompat import cn.openp2p.ui.login.LoginActivity import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch +import openp2p.Openp2p + -class OpenP2PService : VpnService() { +class OpenP2PService : Service() { companion object { private val LOG_TAG = OpenP2PService::class.simpleName } @@ -21,39 +26,90 @@ class OpenP2PService : VpnService() { } private val binder = LocalBinder() - private lateinit var network: openp2p.P2PNetwork + private lateinit var network: openp2p.P2PNetwork + private lateinit var mToken: String + private var running:Boolean =true override fun onCreate() { - Log.i("xiao","onCreate - Thread ID = " + Thread.currentThread().id) + Log.i(LOG_TAG, "onCreate - Thread ID = " + Thread.currentThread().id) + var channelId: String? = null + channelId = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + createNotificationChannel("kim.hsl", "ForegroundService") + } else { + "" + } + val notificationIntent = Intent(this, LoginActivity::class.java) + + val pendingIntent = PendingIntent.getActivity( + this, 0, + notificationIntent, 0 + ) + + val notification = channelId?.let { + NotificationCompat.Builder(this, it) + // .setSmallIcon(R.mipmap.app_icon) + .setContentTitle("My Awesome App") + .setContentText("Doing some work...") + .setContentIntent(pendingIntent).build() + } + + startForeground(1337, notification) super.onCreate() } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { - Log.i("xiao", "onStartCommand - startId = " + startId + ", Thread ID = " + Thread.currentThread().id) + Log.i( + LOG_TAG, + "onStartCommand - startId = " + startId + ", Thread ID = " + Thread.currentThread().id + ) return super.onStartCommand(intent, flags, startId) } override fun onBind(p0: Intent?): IBinder? { + + val token = p0?.getStringExtra("token") + Log.i(LOG_TAG, "onBind - Thread ID = " + Thread.currentThread().id + token) + GlobalScope.launch { + network = Openp2p.runAsModule(getExternalFilesDir(null).toString(), token, 0, 1) + val isConnect = network.connect(30000) // ms + Log.i(OpenP2PService.LOG_TAG, "login result: " + isConnect.toString()); + do { + Thread.sleep(1000) + }while(network.connect(30000)&&running) + stopSelf() + } return binder } override fun onDestroy() { - Log.i("xiao", "onDestroy - Thread ID = " + Thread.currentThread().id) + Log.i(LOG_TAG, "onDestroy - Thread ID = " + Thread.currentThread().id) super.onDestroy() } - fun onStart(token:String){ - GlobalScope.launch { - do { - network =Openp2p.runAsModule(getExternalFilesDir(null).toString(), token, 0) - val isConnect = network.connect(30000) // ms - Log.i(OpenP2PService.LOG_TAG, "login result: " + isConnect.toString()); - } while(!network?.connect(10000)) - } + override fun onUnbind(intent: Intent?): Boolean { + Log.i(LOG_TAG, "onUnbind - Thread ID = " + Thread.currentThread().id) + stopSelf() + return super.onUnbind(intent) } - fun isConnected(): Boolean{ + fun isConnected(): Boolean { if (!::network.isInitialized) return false return network?.connect(1000) } + fun stop() { + running=false + stopSelf() + } + @RequiresApi(Build.VERSION_CODES.O) + private fun createNotificationChannel(channelId: String, channelName: String): String? { + val chan = NotificationChannel( + channelId, + channelName, NotificationManager.IMPORTANCE_NONE + ) + chan.lightColor = Color.BLUE + chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE + val service = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + service.createNotificationChannel(chan) + return channelId + } } \ No newline at end of file diff --git a/app/app/src/main/java/cn/openp2p/ui/login/LoginActivity.kt b/app/app/src/main/java/cn/openp2p/ui/login/LoginActivity.kt index 07d0f41..93cd3f5 100644 --- a/app/app/src/main/java/cn/openp2p/ui/login/LoginActivity.kt +++ b/app/app/src/main/java/cn/openp2p/ui/login/LoginActivity.kt @@ -1,19 +1,26 @@ package cn.openp2p.ui.login +import android.annotation.SuppressLint import android.app.Activity +import android.app.ActivityManager +import android.app.Notification +import android.app.PendingIntent import android.content.ComponentName import android.content.Context import android.content.Intent import android.content.ServiceConnection import android.net.Uri import android.net.VpnService +import android.os.Build import android.os.Bundle import android.os.IBinder import android.text.Editable import android.text.TextWatcher +import android.util.Log import android.view.View import android.widget.EditText import android.widget.Toast +import androidx.annotation.RequiresApi import androidx.annotation.StringRes import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.Observer @@ -23,17 +30,18 @@ import cn.openp2p.R import cn.openp2p.databinding.ActivityLoginBinding import openp2p.Openp2p import kotlin.concurrent.thread +import kotlin.system.exitProcess class LoginActivity : AppCompatActivity() { companion object { private val LOG_TAG = LoginActivity::class.simpleName } + private val connection = object : ServiceConnection { override fun onServiceConnected(className: ComponentName, service: IBinder) { val binder = service as OpenP2PService.LocalBinder mService = binder.getService() - mService.onStart(mToken) } override fun onServiceDisconnected(className: ComponentName) { @@ -43,7 +51,7 @@ class LoginActivity : AppCompatActivity() { private lateinit var loginViewModel: LoginViewModel private lateinit var binding: ActivityLoginBinding private lateinit var mService: OpenP2PService - private var mToken: String="" + @RequiresApi(Build.VERSION_CODES.O) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -52,7 +60,7 @@ class LoginActivity : AppCompatActivity() { val token = binding.token val login = binding.login - val onlineState=binding.onlineState + val onlineState = binding.onlineState val openp2pLog = binding.openp2pLog val profile = binding.profile val loading = binding.loading @@ -70,7 +78,6 @@ class LoginActivity : AppCompatActivity() { token.error = getString(loginState.passwordError) } }) - mToken=token.text.toString() val intent1 = VpnService.prepare(this) ?: return loginViewModel.loginResult.observe(this@LoginActivity, Observer { val loginResult = it ?: return@Observer @@ -102,59 +109,57 @@ class LoginActivity : AppCompatActivity() { ) } -// setOnEditorActionListener { _, actionId, _ -> -// when (actionId) { -// EditorInfo.IME_ACTION_DONE -> -// loginViewModel.login( -// "username.text.toString()", -// token.text.toString() -// ) -// } -// false -// } - -// openp2pLog.setText(getExternalFilesDir(null).toString()) openp2pLog.setText(R.string.phone_setting) token.setText(Openp2p.getToken(getExternalFilesDir(null).toString())) login.setOnClickListener { -// loading.visibility = View.VISIBLE -// loginViewModel.login(username.text.toString(), password.text.toString()) - -// startService(Intent(this, OpenP2PService::class.java)) - val intent = Intent(this@LoginActivity,OpenP2PService::class.java) + if (login.text.toString()=="退出"){ +// val intent = Intent(this@LoginActivity, OpenP2PService::class.java) +// stopService(intent) + Log.i(LOG_TAG, "quit") + mService.stop() + unbindService(connection) + val intent = Intent(this@LoginActivity, OpenP2PService::class.java) + stopService(intent) + exitAPP() + } + login.setText("退出") + Log.i(LOG_TAG, "start") + val intent = Intent(this@LoginActivity, OpenP2PService::class.java) + intent.putExtra("token", token.text.toString()) bindService(intent, connection, Context.BIND_AUTO_CREATE) + startService(intent) thread { do { - Thread.sleep(3000) + Thread.sleep(1000) if (!::mService.isInitialized) continue val isConnect = mService.isConnected() +// Log.i(LOG_TAG, "mService.isConnected() = " + isConnect.toString()) runOnUiThread { - if (isConnect) { - onlineState.setText("在线") - } else { - onlineState.setText("离线") + if (isConnect) { + onlineState.setText("在线") + } else { + onlineState.setText("离线") + } } - } - } while(true) + } while (true) } } } } -// fun listenProgress() { -// Thread { -// while (progress < MsgService.MAX_PROGRESS) { -// progress = msgService.getProgress() -// mProgressBar.setProgress(progress) -// try { -// Thread.sleep(1000) -// } catch (e: InterruptedException) { -// e.printStackTrace() -// } -// } -// }.start() -// } + @RequiresApi(Build.VERSION_CODES.LOLLIPOP) + @SuppressLint("ServiceCast") + fun exitAPP() { + val activityManager = + applicationContext?.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager + val appTaskList = activityManager.appTasks + + for (i in appTaskList.indices) { + appTaskList[i].finishAndRemoveTask() + } + exitProcess(0) + } private fun updateUiWithUser(model: LoggedInUserView) { val welcome = getString(R.string.welcome) diff --git a/app/app/src/main/res/drawable/icon.xml b/app/app/src/main/res/drawable/icon.xml new file mode 100644 index 0000000..ea2eee6 --- /dev/null +++ b/app/app/src/main/res/drawable/icon.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/core/install.go b/core/install.go index aaaefdb..f482693 100644 --- a/core/install.go +++ b/core/install.go @@ -17,7 +17,7 @@ import ( // ./openp2p install -node hhd1207-222 -token YOUR-TOKEN -sharebandwidth 0 -peernode hhdhome-n1 -dstip 127.0.0.1 -dstport 50022 -protocol tcp -srcport 22 func install() { gLog.Println(LvINFO, "openp2p start. version: ", OpenP2PVersion) - gLog.Println(LvINFO, "Contact: QQ: 477503927, Email: openp2p.cn@gmail.com") + gLog.Println(LvINFO, "Contact: QQ: 16947733, Email: openp2p.cn@gmail.com") gLog.Println(LvINFO, "install start") defer gLog.Println(LvINFO, "install end") // auto uninstall diff --git a/core/nat.go b/core/nat.go index 75db2fe..0974c92 100644 --- a/core/nat.go +++ b/core/nat.go @@ -51,6 +51,8 @@ func natTCP(serverHost string, serverPort int, localPort int) (publicIP string, } func natTest(serverHost string, serverPort int, localPort int) (publicIP string, publicPort int, err error) { + gLog.Println(LvDEBUG, "natTest start") + defer gLog.Println(LvDEBUG, "natTest end") conn, err := net.ListenPacket("udp", fmt.Sprintf(":%d", localPort)) if err != nil { gLog.Println(LvERROR, "natTest listen udp error:", err) @@ -113,6 +115,7 @@ func publicIPTest(publicIP string, echoPort int) (hasPublicIP int, hasUPNPorNATP var wg sync.WaitGroup wg.Add(1) go func() { + gLog.Println(LvDEBUG, "echo server start") var err error echoConn, err = net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: echoPort}) if err != nil { @@ -129,6 +132,7 @@ func publicIPTest(publicIP string, echoPort int) (hasPublicIP int, hasUPNPorNATP return } echoConn.WriteToUDP(buf[0:n], addr) + gLog.Println(LvDEBUG, "echo server end") }() wg.Wait() // wait echo udp defer echoConn.Close() @@ -136,6 +140,7 @@ func publicIPTest(publicIP string, echoPort int) (hasPublicIP int, hasUPNPorNATP for i := 0; i < 2; i++ { if i == 1 { // test upnp or nat-pmp + gLog.Println(LvDEBUG, "upnp test start") nat, err := Discover() if err != nil || nat == nil { gLog.Println(LvDEBUG, "could not perform UPNP discover:", err) diff --git a/core/openp2p.go b/core/openp2p.go index e49613c..f52b909 100644 --- a/core/openp2p.go +++ b/core/openp2p.go @@ -43,7 +43,7 @@ func Run() { } parseParams("") gLog.Println(LvINFO, "openp2p start. version: ", OpenP2PVersion) - gLog.Println(LvINFO, "Contact: QQ: 477503927, Email: openp2p.cn@gmail.com") + gLog.Println(LvINFO, "Contact: QQ group 16947733, Email openp2p.cn@gmail.com") if gConf.daemonMode { d := daemon{} @@ -67,18 +67,21 @@ var network *P2PNetwork // for Android app // gomobile not support uint64 exported to java -func RunAsModule(baseDir string, token string, bw int) *P2PNetwork { +func RunAsModule(baseDir string, token string, bw int, logLevel int) *P2PNetwork { rand.Seed(time.Now().UnixNano()) os.Chdir(baseDir) // for system service gLog = NewLogger(baseDir, ProducnName, LvDEBUG, 1024*1024, LogFileAndConsole) - // TODO: install sub command, deamon process + parseParams("") - n, _ := strconv.ParseUint(token, 10, 64) - gConf.setToken(n) - gConf.setShareBandwidth(0) + n, err := strconv.ParseUint(token, 10, 64) + if err == nil { + gConf.setToken(n) + } + gLog.setLevel(LogLevel(logLevel)) + gConf.setShareBandwidth(bw) gLog.Println(LvINFO, "openp2p start. version: ", OpenP2PVersion) - gLog.Println(LvINFO, "Contact: QQ: 477503927, Email: openp2p.cn@gmail.com") + gLog.Println(LvINFO, "Contact: QQ group 16947733, Email openp2p.cn@gmail.com") gLog.Println(LvINFO, &gConf) network = P2PNetworkInstance(&gConf.Network) diff --git a/core/p2pnetwork.go b/core/p2pnetwork.go index c5c5c0f..30dd76f 100644 --- a/core/p2pnetwork.go +++ b/core/p2pnetwork.go @@ -64,6 +64,7 @@ func P2PNetworkInstance(config *NetworkConfig) *P2PNetwork { } func (pn *P2PNetwork) run() { + go pn.readLoop() go pn.autorunApp() heartbeatTimer := time.NewTicker(NetworkHeartbeatTime) for pn.running { @@ -487,7 +488,6 @@ func (pn *P2PNetwork) init() error { err = errors.New("get local ip failed") break } - go pn.readLoop() pn.config.mac = getmac(pn.config.localIP) pn.config.os = getOsName() diff --git a/go.mod b/go.mod index 3d0d367..23909fb 100644 --- a/go.mod +++ b/go.mod @@ -20,6 +20,7 @@ require ( github.com/nxadm/tail v1.4.8 // indirect github.com/onsi/ginkgo v1.16.4 // indirect golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect + golang.org/x/mobile v0.0.0-20221020085226-b36e6246172e // indirect golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect golang.org/x/tools v0.1.12 // indirect