mirror of
				https://github.com/PurpleI2P/i2pd.git
				synced 2025-11-04 08:30:46 +00:00 
			
		
		
		
	[android] build libi2pd staticly, add update strings, fix messages
This commit is contained in:
		
							parent
							
								
									65c2c7d80b
								
							
						
					
					
						commit
						d7609f119c
					
				
					 15 changed files with 462 additions and 433 deletions
				
			
		| 
						 | 
				
			
			@ -28,15 +28,17 @@ android {
 | 
			
		|||
        applicationId "org.purplei2p.i2pd"
 | 
			
		||||
        targetSdkVersion 28
 | 
			
		||||
        minSdkVersion 14
 | 
			
		||||
        versionCode 1
 | 
			
		||||
        versionCode 2220
 | 
			
		||||
        versionName "2.22.0"
 | 
			
		||||
        ndk {
 | 
			
		||||
            abiFilters 'armeabi-v7a'
 | 
			
		||||
            abiFilters 'x86'
 | 
			
		||||
            //abiFilters 'arm64-v8a'
 | 
			
		||||
            //abiFilters 'x86_64'
 | 
			
		||||
        }
 | 
			
		||||
        externalNativeBuild {
 | 
			
		||||
            ndkBuild {
 | 
			
		||||
                arguments "-j4"
 | 
			
		||||
                arguments "-j3"
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -49,6 +51,15 @@ android {
 | 
			
		|||
            assets.srcDirs = ['assets']
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    splits {
 | 
			
		||||
        abi {
 | 
			
		||||
            // change that to true if you need splitted apk
 | 
			
		||||
            enable false 
 | 
			
		||||
            reset()
 | 
			
		||||
            include "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
 | 
			
		||||
            universalApk true
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    signingConfigs {
 | 
			
		||||
        orignal {
 | 
			
		||||
            storeFile file("i2pdapk.jks")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,12 +1,13 @@
 | 
			
		|||
APP_ABI := armeabi-v7a x86
 | 
			
		||||
APP_PLATFORM := android-14
 | 
			
		||||
#APP_ABI := armeabi-v7a x86
 | 
			
		||||
#APP_PLATFORM := android-14
 | 
			
		||||
 | 
			
		||||
# ABI arm64-v8a and x86_64 supported only from platform-21
 | 
			
		||||
#APP_ABI := arm64-v8a x86_64
 | 
			
		||||
#APP_PLATFORM := android-21
 | 
			
		||||
 | 
			
		||||
NDK_TOOLCHAIN_VERSION := clang
 | 
			
		||||
APP_STL := c++_shared
 | 
			
		||||
#APP_STL := c++_shared
 | 
			
		||||
APP_STL := c++_static
 | 
			
		||||
 | 
			
		||||
# Enable c++11 extensions in source code
 | 
			
		||||
APP_CPPFLAGS += -std=c++11 -fexceptions -frtti
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,7 +39,7 @@ namespace android
 | 
			
		|||
		emit resultReady();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    Controller::Controller(DaemonAndroidImpl& daemon):
 | 
			
		||||
	Controller::Controller(DaemonAndroidImpl& daemon):
 | 
			
		||||
		m_Daemon (daemon)
 | 
			
		||||
	{
 | 
			
		||||
		Worker *worker = new Worker (m_Daemon);
 | 
			
		||||
| 
						 | 
				
			
			@ -57,19 +57,19 @@ namespace android
 | 
			
		|||
		workerThread.quit();
 | 
			
		||||
		workerThread.wait();
 | 
			
		||||
		Log.d(TAG"Waiting for daemon worker thread finished.");
 | 
			
		||||
        if(m_Daemon.isRunning())
 | 
			
		||||
        {
 | 
			
		||||
		    Log.d(TAG"Stopping the daemon...");
 | 
			
		||||
            m_Daemon.stop();
 | 
			
		||||
		    Log.d(TAG"Stopped the daemon.");
 | 
			
		||||
		if(m_Daemon.isRunning())
 | 
			
		||||
		{
 | 
			
		||||
			Log.d(TAG"Stopping the daemon...");
 | 
			
		||||
			m_Daemon.stop();
 | 
			
		||||
			Log.d(TAG"Stopped the daemon.");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
*/
 | 
			
		||||
	DaemonAndroidImpl::DaemonAndroidImpl ()
 | 
			
		||||
		//:
 | 
			
		||||
        /*mutex(nullptr), */
 | 
			
		||||
        //m_IsRunning(false),
 | 
			
		||||
        //m_RunningChangedCallback(nullptr)
 | 
			
		||||
		/*mutex(nullptr), */
 | 
			
		||||
		//m_IsRunning(false),
 | 
			
		||||
		//m_RunningChangedCallback(nullptr)
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -82,9 +82,9 @@ namespace android
 | 
			
		|||
	{
 | 
			
		||||
		//mutex=new QMutex(QMutex::Recursive);
 | 
			
		||||
		//setRunningCallback(0);
 | 
			
		||||
        //m_IsRunning=false;
 | 
			
		||||
		
 | 
			
		||||
		// make sure assets are ready before proceed	
 | 
			
		||||
		//m_IsRunning=false;
 | 
			
		||||
 | 
			
		||||
		// make sure assets are ready before proceed
 | 
			
		||||
		i2p::fs::DetectDataDir("", false);
 | 
			
		||||
		int numAttempts = 0;
 | 
			
		||||
		do
 | 
			
		||||
| 
						 | 
				
			
			@ -93,7 +93,7 @@ namespace android
 | 
			
		|||
			numAttempts++;
 | 
			
		||||
			std::this_thread::sleep_for (std::chrono::seconds(1)); // otherwise wait for 1 more second
 | 
			
		||||
		}
 | 
			
		||||
		while (numAttempts <= 10); // 10 seconds max	
 | 
			
		||||
		while (numAttempts <= 10); // 10 seconds max
 | 
			
		||||
		return Daemon.init(argc,argv);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -125,16 +125,16 @@ namespace android
 | 
			
		|||
 | 
			
		||||
	bool DaemonAndroidImpl::isRunning()
 | 
			
		||||
	{
 | 
			
		||||
        return m_IsRunning;
 | 
			
		||||
		return m_IsRunning;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void DaemonAndroidImpl::setRunning(bool newValue)
 | 
			
		||||
	{
 | 
			
		||||
        bool oldValue = m_IsRunning;
 | 
			
		||||
		bool oldValue = m_IsRunning;
 | 
			
		||||
		if(oldValue!=newValue)
 | 
			
		||||
		{
 | 
			
		||||
            m_IsRunning = newValue;
 | 
			
		||||
		    if(m_RunningChangedCallback)
 | 
			
		||||
			m_IsRunning = newValue;
 | 
			
		||||
			if(m_RunningChangedCallback)
 | 
			
		||||
				m_RunningChangedCallback();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -183,14 +183,14 @@ namespace android
 | 
			
		|||
		catch (boost::exception& ex)
 | 
			
		||||
		{
 | 
			
		||||
			std::stringstream ss;
 | 
			
		||||
		    ss << boost::diagnostic_information(ex);
 | 
			
		||||
		    return ss.str();
 | 
			
		||||
			ss << boost::diagnostic_information(ex);
 | 
			
		||||
			return ss.str();
 | 
			
		||||
		}
 | 
			
		||||
		catch (std::exception& ex)
 | 
			
		||||
		{
 | 
			
		||||
			std::stringstream ss;
 | 
			
		||||
		    ss << ex.what();
 | 
			
		||||
		    return ss.str();
 | 
			
		||||
			ss << ex.what();
 | 
			
		||||
			return ss.str();
 | 
			
		||||
		}
 | 
			
		||||
		catch(...)
 | 
			
		||||
		{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,45 +7,45 @@ namespace i2p
 | 
			
		|||
{
 | 
			
		||||
namespace android
 | 
			
		||||
{
 | 
			
		||||
    class DaemonAndroidImpl
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
	class DaemonAndroidImpl
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
 | 
			
		||||
		DaemonAndroidImpl ();
 | 
			
		||||
		~DaemonAndroidImpl ();
 | 
			
		||||
 | 
			
		||||
        //typedef void (*runningChangedCallback)();
 | 
			
		||||
		//typedef void (*runningChangedCallback)();
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * @return success
 | 
			
		||||
         */
 | 
			
		||||
        bool init(int argc, char* argv[]);
 | 
			
		||||
        void start();
 | 
			
		||||
        void stop();
 | 
			
		||||
        void restart();
 | 
			
		||||
        //void setRunningCallback(runningChangedCallback cb);
 | 
			
		||||
        //bool isRunning();
 | 
			
		||||
    private:
 | 
			
		||||
        //void setRunning(bool running);
 | 
			
		||||
		/**
 | 
			
		||||
		 * @return success
 | 
			
		||||
		 */
 | 
			
		||||
		bool init(int argc, char* argv[]);
 | 
			
		||||
		void start();
 | 
			
		||||
		void stop();
 | 
			
		||||
		void restart();
 | 
			
		||||
		//void setRunningCallback(runningChangedCallback cb);
 | 
			
		||||
		//bool isRunning();
 | 
			
		||||
	private:
 | 
			
		||||
		//void setRunning(bool running);
 | 
			
		||||
	private:
 | 
			
		||||
		//QMutex* mutex;
 | 
			
		||||
        //bool m_IsRunning;
 | 
			
		||||
		//bool m_IsRunning;
 | 
			
		||||
		//runningChangedCallback m_RunningChangedCallback;
 | 
			
		||||
    };
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * returns "ok" if daemon init failed
 | 
			
		||||
	 * returns errinfo if daemon initialized and started okay
 | 
			
		||||
	 */
 | 
			
		||||
    std::string start();
 | 
			
		||||
	std::string start();
 | 
			
		||||
 | 
			
		||||
    // stops the daemon
 | 
			
		||||
    void stop();
 | 
			
		||||
	// stops the daemon
 | 
			
		||||
	void stop();
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
	/*
 | 
			
		||||
	class Worker : public QObject
 | 
			
		||||
    {
 | 
			
		||||
        Q_OBJECT
 | 
			
		||||
	{
 | 
			
		||||
		Q_OBJECT
 | 
			
		||||
	public:
 | 
			
		||||
 | 
			
		||||
		Worker (DaemonAndroidImpl& daemon);
 | 
			
		||||
| 
						 | 
				
			
			@ -54,33 +54,33 @@ namespace android
 | 
			
		|||
 | 
			
		||||
		DaemonAndroidImpl& m_Daemon;
 | 
			
		||||
 | 
			
		||||
    public slots:
 | 
			
		||||
        void startDaemon();
 | 
			
		||||
        void restartDaemon();
 | 
			
		||||
        void stopDaemon();
 | 
			
		||||
	public slots:
 | 
			
		||||
		void startDaemon();
 | 
			
		||||
		void restartDaemon();
 | 
			
		||||
		void stopDaemon();
 | 
			
		||||
 | 
			
		||||
    signals:
 | 
			
		||||
        void resultReady();
 | 
			
		||||
    };
 | 
			
		||||
	signals:
 | 
			
		||||
		void resultReady();
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
    class Controller : public QObject
 | 
			
		||||
    {
 | 
			
		||||
        Q_OBJECT
 | 
			
		||||
        QThread workerThread;
 | 
			
		||||
    public:
 | 
			
		||||
        Controller(DaemonAndroidImpl& daemon);
 | 
			
		||||
        ~Controller();
 | 
			
		||||
	class Controller : public QObject
 | 
			
		||||
	{
 | 
			
		||||
		Q_OBJECT
 | 
			
		||||
		QThread workerThread;
 | 
			
		||||
	public:
 | 
			
		||||
		Controller(DaemonAndroidImpl& daemon);
 | 
			
		||||
		~Controller();
 | 
			
		||||
	private:
 | 
			
		||||
		DaemonAndroidImpl& m_Daemon;
 | 
			
		||||
 | 
			
		||||
    public slots:
 | 
			
		||||
        void handleResults(){}
 | 
			
		||||
    signals:
 | 
			
		||||
        void startDaemon();
 | 
			
		||||
        void stopDaemon();
 | 
			
		||||
        void restartDaemon();
 | 
			
		||||
    };
 | 
			
		||||
    */
 | 
			
		||||
	public slots:
 | 
			
		||||
		void handleResults(){}
 | 
			
		||||
	signals:
 | 
			
		||||
		void startDaemon();
 | 
			
		||||
		void stopDaemon();
 | 
			
		||||
		void restartDaemon();
 | 
			
		||||
	};
 | 
			
		||||
	*/
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,3 @@
 | 
			
		|||
 | 
			
		||||
//#include <string.h>
 | 
			
		||||
#include <jni.h>
 | 
			
		||||
#include "org_purplei2p_i2pd_I2PD_JNI.h"
 | 
			
		||||
#include "DaemonAndroid.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -7,65 +5,64 @@
 | 
			
		|||
#include "Transports.h"
 | 
			
		||||
 | 
			
		||||
JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getABICompiledWith
 | 
			
		||||
  (JNIEnv * env, jclass clazz) {
 | 
			
		||||
	(JNIEnv * env, jclass clazz) {
 | 
			
		||||
#if defined(__arm__)
 | 
			
		||||
  #if defined(__ARM_ARCH_7A__)
 | 
			
		||||
    #if defined(__ARM_NEON__)
 | 
			
		||||
      #if defined(__ARM_PCS_VFP)
 | 
			
		||||
        #define ABI "armeabi-v7a/NEON (hard-float)"
 | 
			
		||||
      #else
 | 
			
		||||
        #define ABI "armeabi-v7a/NEON"
 | 
			
		||||
      #endif
 | 
			
		||||
    #else
 | 
			
		||||
      #if defined(__ARM_PCS_VFP)
 | 
			
		||||
        #define ABI "armeabi-v7a (hard-float)"
 | 
			
		||||
      #else
 | 
			
		||||
        #define ABI "armeabi-v7a"
 | 
			
		||||
      #endif
 | 
			
		||||
    #endif
 | 
			
		||||
  #else
 | 
			
		||||
   #define ABI "armeabi"
 | 
			
		||||
  #endif
 | 
			
		||||
#elif defined(__i386__)
 | 
			
		||||
   #define ABI "x86"
 | 
			
		||||
#elif defined(__x86_64__)
 | 
			
		||||
   #define ABI "x86_64"
 | 
			
		||||
#elif defined(__mips64)  /* mips64el-* toolchain defines __mips__ too */
 | 
			
		||||
   #define ABI "mips64"
 | 
			
		||||
#elif defined(__mips__)
 | 
			
		||||
   #define ABI "mips"
 | 
			
		||||
#elif defined(__aarch64__)
 | 
			
		||||
   #define ABI "arm64-v8a"
 | 
			
		||||
#else
 | 
			
		||||
   #define ABI "unknown"
 | 
			
		||||
	#if defined(__ARM_ARCH_7A__)
 | 
			
		||||
		#if defined(__ARM_NEON__)
 | 
			
		||||
			#if defined(__ARM_PCS_VFP)
 | 
			
		||||
				#define ABI "armeabi-v7a/NEON (hard-float)"
 | 
			
		||||
				#else
 | 
			
		||||
				#define ABI "armeabi-v7a/NEON"
 | 
			
		||||
			#endif
 | 
			
		||||
			#else
 | 
			
		||||
			#if defined(__ARM_PCS_VFP)
 | 
			
		||||
				#define ABI "armeabi-v7a (hard-float)"
 | 
			
		||||
				#else
 | 
			
		||||
				#define ABI "armeabi-v7a"
 | 
			
		||||
			#endif
 | 
			
		||||
		#endif
 | 
			
		||||
		#else
 | 
			
		||||
		#define ABI "armeabi"
 | 
			
		||||
	#endif
 | 
			
		||||
	#elif defined(__i386__)
 | 
			
		||||
	#define ABI "x86"
 | 
			
		||||
	#elif defined(__x86_64__)
 | 
			
		||||
	#define ABI "x86_64"
 | 
			
		||||
	#elif defined(__mips64)  /* mips64el-* toolchain defines __mips__ too */
 | 
			
		||||
	#define ABI "mips64"
 | 
			
		||||
	#elif defined(__mips__)
 | 
			
		||||
	#define ABI "mips"
 | 
			
		||||
	#elif defined(__aarch64__)
 | 
			
		||||
	#define ABI "arm64-v8a"
 | 
			
		||||
	#else
 | 
			
		||||
	#define ABI "unknown"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    return env->NewStringUTF(ABI);
 | 
			
		||||
	return env->NewStringUTF(ABI);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startDaemon
 | 
			
		||||
  (JNIEnv * env, jclass clazz) {
 | 
			
		||||
	(JNIEnv * env, jclass clazz) {
 | 
			
		||||
	return env->NewStringUTF(i2p::android::start().c_str());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopDaemon
 | 
			
		||||
  (JNIEnv * env, jclass clazz) {
 | 
			
		||||
	(JNIEnv * env, jclass clazz) {
 | 
			
		||||
	i2p::android::stop();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopAcceptingTunnels
 | 
			
		||||
  (JNIEnv * env, jclass clazz) {
 | 
			
		||||
	(JNIEnv * env, jclass clazz) {
 | 
			
		||||
	i2p::context.SetAcceptsTunnels (false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startAcceptingTunnels
 | 
			
		||||
  (JNIEnv * env, jclass clazz) {
 | 
			
		||||
	(JNIEnv * env, jclass clazz) {
 | 
			
		||||
	i2p::context.SetAcceptsTunnels (true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_onNetworkStateChanged
 | 
			
		||||
  (JNIEnv * env, jclass clazz, jboolean isConnected)
 | 
			
		||||
{
 | 
			
		||||
	(JNIEnv * env, jclass clazz, jboolean isConnected) {
 | 
			
		||||
	bool isConnectedBool = (bool) isConnected;
 | 
			
		||||
	i2p::transport::transports.SetOnline (isConnectedBool);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,22 +13,22 @@ extern "C" {
 | 
			
		|||
 * Signature: ()Ljava/lang/String;
 | 
			
		||||
 */
 | 
			
		||||
JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getABICompiledWith
 | 
			
		||||
  (JNIEnv *, jclass);
 | 
			
		||||
	(JNIEnv *, jclass);
 | 
			
		||||
 | 
			
		||||
JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startDaemon
 | 
			
		||||
  (JNIEnv *, jclass);
 | 
			
		||||
	(JNIEnv *, jclass);
 | 
			
		||||
 | 
			
		||||
JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopDaemon
 | 
			
		||||
  (JNIEnv *, jclass);
 | 
			
		||||
	(JNIEnv *, jclass);
 | 
			
		||||
 | 
			
		||||
JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopAcceptingTunnels
 | 
			
		||||
  (JNIEnv *, jclass);
 | 
			
		||||
	(JNIEnv *, jclass);
 | 
			
		||||
 | 
			
		||||
JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startAcceptingTunnels
 | 
			
		||||
  (JNIEnv *, jclass);
 | 
			
		||||
	(JNIEnv *, jclass);
 | 
			
		||||
 | 
			
		||||
JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_onNetworkStateChanged
 | 
			
		||||
  (JNIEnv * env, jclass clazz, jboolean isConnected);
 | 
			
		||||
	(JNIEnv * env, jclass clazz, jboolean isConnected);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										19
									
								
								android/res/values-ru/strings.xml
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										19
									
								
								android/res/values-ru/strings.xml
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,19 @@
 | 
			
		|||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<resources>
 | 
			
		||||
    <string name="app_name">i2pd</string>
 | 
			
		||||
    <string name="action_stop">Остановить</string>
 | 
			
		||||
    <string name="action_graceful_stop">Корректная остановка</string>
 | 
			
		||||
    <string name="action_cancel_graceful_stop">Отменить мягкую остановку</string>
 | 
			
		||||
    <string name="graceful_stop_is_already_in_progress">Мягкая остановка уже запущена</string>
 | 
			
		||||
    <string name="graceful_stop_is_in_progress">Мягкая остановка запущена</string>
 | 
			
		||||
    <string name="already_stopped">Уже остановлено</string>
 | 
			
		||||
    <string name="uninitialized">Приложение инициализируется</string>
 | 
			
		||||
    <string name="starting">Приложение запускается</string>
 | 
			
		||||
    <string name="jniLibraryLoaded">Загружены JNI библиотеки</string>
 | 
			
		||||
    <string name="startedOkay">Приложение запущено</string>
 | 
			
		||||
    <string name="startFailed">Запуск не удался</string>
 | 
			
		||||
    <string name="gracefulShutdownInProgress">Мягкая остановка запущена</string>
 | 
			
		||||
    <string name="stopped">Приложение было остановлено</string>
 | 
			
		||||
    <string name="remaining">осталось</string>
 | 
			
		||||
    <string name="title_activity_i2_pdperms_asker_prompt">Запрос</string>
 | 
			
		||||
</resources>
 | 
			
		||||
| 
						 | 
				
			
			@ -1,19 +1,19 @@
 | 
			
		|||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<resources>
 | 
			
		||||
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
 | 
			
		||||
    <string name="app_name">i2pd</string>
 | 
			
		||||
    <string name="action_stop">Stop</string>
 | 
			
		||||
    <string name="action_graceful_stop">Graceful Stop</string>
 | 
			
		||||
	<string name="action_cancel_graceful_stop">Cancel Graceful Stop</string>
 | 
			
		||||
    <string name="action_cancel_graceful_stop">Cancel Graceful Stop</string>
 | 
			
		||||
    <string name="graceful_stop_is_already_in_progress">Graceful stop is already in progress</string>
 | 
			
		||||
    <string name="graceful_stop_is_in_progress">Graceful stop is in progress</string>
 | 
			
		||||
    <string name="already_stopped">Already stopped</string>
 | 
			
		||||
    <string name="uninitialized">i2pd initializing</string>
 | 
			
		||||
    <string name="starting">i2pd is starting</string>
 | 
			
		||||
    <string name="jniLibraryLoaded">i2pd: loaded JNI libraries</string>
 | 
			
		||||
    <string name="startedOkay">i2pd started</string>
 | 
			
		||||
    <string name="startFailed">i2pd start failed</string>
 | 
			
		||||
    <string name="gracefulShutdownInProgress">i2pd: graceful shutdown in progress</string>
 | 
			
		||||
    <string name="stopped">i2pd has stopped</string>
 | 
			
		||||
    <string name="uninitialized">Application initializing</string>
 | 
			
		||||
    <string name="starting">Application starting</string>
 | 
			
		||||
    <string name="jniLibraryLoaded">Loaded JNI libraries</string>
 | 
			
		||||
    <string name="startedOkay">Application Started</string>
 | 
			
		||||
    <string name="startFailed">Start failed</string>
 | 
			
		||||
    <string name="gracefulShutdownInProgress">Graceful shutdown in progress</string>
 | 
			
		||||
    <string name="stopped">Application stopped</string>
 | 
			
		||||
    <string name="remaining">remaining</string>
 | 
			
		||||
    <string name="title_activity_i2_pdperms_asker_prompt">Prompt</string>
 | 
			
		||||
</resources>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,8 +2,8 @@ package org.purplei2p.i2pd;
 | 
			
		|||
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import android.util.Log;
 | 
			
		||||
import org.purplei2p.i2pd.R;
 | 
			
		||||
 | 
			
		||||
public class DaemonSingleton {
 | 
			
		||||
	private static final String TAG="i2pd";
 | 
			
		||||
| 
						 | 
				
			
			@ -43,24 +43,24 @@ public class DaemonSingleton {
 | 
			
		|||
	private volatile boolean startedOkay;
 | 
			
		||||
 | 
			
		||||
	public enum State {
 | 
			
		||||
        uninitialized(R.string.uninitialized),
 | 
			
		||||
        starting(R.string.starting),
 | 
			
		||||
        jniLibraryLoaded(R.string.jniLibraryLoaded),
 | 
			
		||||
        startedOkay(R.string.startedOkay),
 | 
			
		||||
        startFailed(R.string.startFailed),
 | 
			
		||||
        gracefulShutdownInProgress(R.string.gracefulShutdownInProgress),
 | 
			
		||||
        stopped(R.string.stopped);
 | 
			
		||||
		uninitialized(R.string.uninitialized),
 | 
			
		||||
		starting(R.string.starting),
 | 
			
		||||
		jniLibraryLoaded(R.string.jniLibraryLoaded),
 | 
			
		||||
		startedOkay(R.string.startedOkay),
 | 
			
		||||
		startFailed(R.string.startFailed),
 | 
			
		||||
		gracefulShutdownInProgress(R.string.gracefulShutdownInProgress),
 | 
			
		||||
		stopped(R.string.stopped);
 | 
			
		||||
 | 
			
		||||
        State(int statusStringResourceId) {
 | 
			
		||||
            this.statusStringResourceId = statusStringResourceId;
 | 
			
		||||
        }
 | 
			
		||||
		State(int statusStringResourceId) {
 | 
			
		||||
			this.statusStringResourceId = statusStringResourceId;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
        private final int statusStringResourceId;
 | 
			
		||||
		private final int statusStringResourceId;
 | 
			
		||||
 | 
			
		||||
        public int getStatusStringResourceId() {
 | 
			
		||||
            return statusStringResourceId;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
		public int getStatusStringResourceId() {
 | 
			
		||||
			return statusStringResourceId;
 | 
			
		||||
		}
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	private volatile State state = State.uninitialized;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,134 +16,133 @@ import android.util.Log;
 | 
			
		|||
import android.widget.Toast;
 | 
			
		||||
 | 
			
		||||
public class ForegroundService extends Service {
 | 
			
		||||
    private static final String TAG="FgService";
 | 
			
		||||
	private static final String TAG="FgService";
 | 
			
		||||
 | 
			
		||||
    private volatile boolean shown;
 | 
			
		||||
	private volatile boolean shown;
 | 
			
		||||
 | 
			
		||||
    private final DaemonSingleton.StateUpdateListener daemonStateUpdatedListener =
 | 
			
		||||
            new DaemonSingleton.StateUpdateListener() {
 | 
			
		||||
	private final DaemonSingleton.StateUpdateListener daemonStateUpdatedListener =
 | 
			
		||||
			new DaemonSingleton.StateUpdateListener() {
 | 
			
		||||
 | 
			
		||||
                @Override
 | 
			
		||||
                public void daemonStateUpdate() {
 | 
			
		||||
                    try {
 | 
			
		||||
                        synchronized (ForegroundService.this) {
 | 
			
		||||
                            if (shown) cancelNotification();
 | 
			
		||||
                            showNotification();
 | 
			
		||||
                        }
 | 
			
		||||
                    } catch (Throwable tr) {
 | 
			
		||||
                        Log.e(TAG,"error ignored",tr);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
				@Override
 | 
			
		||||
				public void daemonStateUpdate() {
 | 
			
		||||
					try {
 | 
			
		||||
						synchronized (ForegroundService.this) {
 | 
			
		||||
							if (shown) cancelNotification();
 | 
			
		||||
							showNotification();
 | 
			
		||||
						}
 | 
			
		||||
					} catch (Throwable tr) {
 | 
			
		||||
						Log.e(TAG,"error ignored",tr);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    private NotificationManager notificationManager;
 | 
			
		||||
	private NotificationManager notificationManager;
 | 
			
		||||
 | 
			
		||||
    // Unique Identification Number for the Notification.
 | 
			
		||||
    // We use it on Notification start, and to cancel it.
 | 
			
		||||
    private int NOTIFICATION = 1;
 | 
			
		||||
	// Unique Identification Number for the Notification.
 | 
			
		||||
	// We use it on Notification start, and to cancel it.
 | 
			
		||||
	private int NOTIFICATION = 1;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Class for clients to access.  Because we know this service always
 | 
			
		||||
     * runs in the same process as its clients, we don't need to deal with
 | 
			
		||||
     * IPC.
 | 
			
		||||
     */
 | 
			
		||||
    public class LocalBinder extends Binder {
 | 
			
		||||
        ForegroundService getService() {
 | 
			
		||||
            return ForegroundService.this;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
	/**
 | 
			
		||||
	 * Class for clients to access.  Because we know this service always
 | 
			
		||||
	 * runs in the same process as its clients, we don't need to deal with
 | 
			
		||||
	 * IPC.
 | 
			
		||||
	 */
 | 
			
		||||
	public class LocalBinder extends Binder {
 | 
			
		||||
		ForegroundService getService() {
 | 
			
		||||
			return ForegroundService.this;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onCreate() {
 | 
			
		||||
        notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
 | 
			
		||||
	@Override
 | 
			
		||||
	public void onCreate() {
 | 
			
		||||
		notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
 | 
			
		||||
 | 
			
		||||
        synchronized (this) {
 | 
			
		||||
            DaemonSingleton.getInstance().addStateChangeListener(daemonStateUpdatedListener);
 | 
			
		||||
            if (!shown) daemonStateUpdatedListener.daemonStateUpdate();
 | 
			
		||||
        }
 | 
			
		||||
        // Tell the user we started.
 | 
			
		||||
//        Toast.makeText(this, R.string.i2pd_service_started, Toast.LENGTH_SHORT).show();
 | 
			
		||||
    }
 | 
			
		||||
		synchronized (this) {
 | 
			
		||||
			DaemonSingleton.getInstance().addStateChangeListener(daemonStateUpdatedListener);
 | 
			
		||||
			if (!shown) daemonStateUpdatedListener.daemonStateUpdate();
 | 
			
		||||
		}
 | 
			
		||||
		// Tell the user we started.
 | 
			
		||||
//		Toast.makeText(this, R.string.i2pd_service_started, Toast.LENGTH_SHORT).show();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public int onStartCommand(Intent intent, int flags, int startId) {
 | 
			
		||||
        Log.i("ForegroundService", "Received start id " + startId + ": " + intent);
 | 
			
		||||
        return START_STICKY;
 | 
			
		||||
    }
 | 
			
		||||
	@Override
 | 
			
		||||
	public int onStartCommand(Intent intent, int flags, int startId) {
 | 
			
		||||
		Log.i("ForegroundService", "Received start id " + startId + ": " + intent);
 | 
			
		||||
		return START_STICKY;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onDestroy() {
 | 
			
		||||
        DaemonSingleton.getInstance().removeStateChangeListener(daemonStateUpdatedListener);
 | 
			
		||||
        cancelNotification();
 | 
			
		||||
    }
 | 
			
		||||
	@Override
 | 
			
		||||
	public void onDestroy() {
 | 
			
		||||
		DaemonSingleton.getInstance().removeStateChangeListener(daemonStateUpdatedListener);
 | 
			
		||||
		cancelNotification();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    private synchronized void cancelNotification() {
 | 
			
		||||
        // Cancel the persistent notification.
 | 
			
		||||
        notificationManager.cancel(NOTIFICATION);
 | 
			
		||||
	private synchronized void cancelNotification() {
 | 
			
		||||
		// Cancel the persistent notification.
 | 
			
		||||
		notificationManager.cancel(NOTIFICATION);
 | 
			
		||||
 | 
			
		||||
        stopForeground(true);
 | 
			
		||||
		stopForeground(true);
 | 
			
		||||
 | 
			
		||||
        // Tell the user we stopped.
 | 
			
		||||
//        Toast.makeText(this, R.string.i2pd_service_stopped, Toast.LENGTH_SHORT).show();
 | 
			
		||||
        shown=false;
 | 
			
		||||
    }
 | 
			
		||||
		// Tell the user we stopped.
 | 
			
		||||
		//Toast.makeText(this, R.string.i2pd_service_stopped, Toast.LENGTH_SHORT).show();
 | 
			
		||||
		shown=false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public IBinder onBind(Intent intent) {
 | 
			
		||||
        return mBinder;
 | 
			
		||||
    }
 | 
			
		||||
	@Override
 | 
			
		||||
	public IBinder onBind(Intent intent) {
 | 
			
		||||
		return mBinder;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    // This is the object that receives interactions from clients.  See
 | 
			
		||||
    // RemoteService for a more complete example.
 | 
			
		||||
    private final IBinder mBinder = new LocalBinder();
 | 
			
		||||
	// This is the object that receives interactions from clients.  See
 | 
			
		||||
	// RemoteService for a more complete example.
 | 
			
		||||
	private final IBinder mBinder = new LocalBinder();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Show a notification while this service is running.
 | 
			
		||||
     */
 | 
			
		||||
    private synchronized void showNotification() {
 | 
			
		||||
        // In this sample, we'll use the same text for the ticker and the expanded notification
 | 
			
		||||
        CharSequence text = getText(DaemonSingleton.getInstance().getState().getStatusStringResourceId());
 | 
			
		||||
	/**
 | 
			
		||||
	 * Show a notification while this service is running.
 | 
			
		||||
	 */
 | 
			
		||||
	private synchronized void showNotification() {
 | 
			
		||||
		// In this sample, we'll use the same text for the ticker and the expanded notification
 | 
			
		||||
		CharSequence text = getText(DaemonSingleton.getInstance().getState().getStatusStringResourceId());
 | 
			
		||||
 | 
			
		||||
        // The PendingIntent to launch our activity if the user selects this notification
 | 
			
		||||
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
 | 
			
		||||
                new Intent(this, I2PDActivity.class), 0);
 | 
			
		||||
		// The PendingIntent to launch our activity if the user selects this notification
 | 
			
		||||
		PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
 | 
			
		||||
				new Intent(this, I2PDActivity.class), 0);
 | 
			
		||||
 | 
			
		||||
        // If earlier version channel ID is not used
 | 
			
		||||
        // https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context)
 | 
			
		||||
        String channelId = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) ? createNotificationChannel() : "";
 | 
			
		||||
		// If earlier version channel ID is not used
 | 
			
		||||
		// https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context)
 | 
			
		||||
		String channelId = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) ? createNotificationChannel() : "";
 | 
			
		||||
 | 
			
		||||
        // Set the info for the views that show in the notification panel.
 | 
			
		||||
        Notification notification = new NotificationCompat.Builder(this, channelId)
 | 
			
		||||
                .setOngoing(true)
 | 
			
		||||
                .setSmallIcon(R.drawable.itoopie_notification_icon) // the status icon
 | 
			
		||||
                .setPriority(Notification.PRIORITY_DEFAULT)
 | 
			
		||||
                .setCategory(Notification.CATEGORY_SERVICE)
 | 
			
		||||
                .setTicker(text) // the status text
 | 
			
		||||
                .setWhen(System.currentTimeMillis()) // the time stamp
 | 
			
		||||
                .setContentTitle(getText(R.string.app_name)) // the label of the entry
 | 
			
		||||
                .setContentText(text) // the contents of the entry
 | 
			
		||||
                .setContentIntent(contentIntent) // The intent to send when the entry is clicked
 | 
			
		||||
                .build();
 | 
			
		||||
		// Set the info for the views that show in the notification panel.
 | 
			
		||||
		Notification notification = new NotificationCompat.Builder(this, channelId)
 | 
			
		||||
				.setOngoing(true)
 | 
			
		||||
				.setSmallIcon(R.drawable.itoopie_notification_icon) // the status icon
 | 
			
		||||
				.setPriority(Notification.PRIORITY_DEFAULT)
 | 
			
		||||
				.setCategory(Notification.CATEGORY_SERVICE)
 | 
			
		||||
				.setTicker(text) // the status text
 | 
			
		||||
				.setWhen(System.currentTimeMillis()) // the time stamp
 | 
			
		||||
				.setContentTitle(getText(R.string.app_name)) // the label of the entry
 | 
			
		||||
				.setContentText(text) // the contents of the entry
 | 
			
		||||
				.setContentIntent(contentIntent) // The intent to send when the entry is clicked
 | 
			
		||||
				.build();
 | 
			
		||||
 | 
			
		||||
        // Send the notification.
 | 
			
		||||
        //mNM.notify(NOTIFICATION, notification);
 | 
			
		||||
        startForeground(NOTIFICATION, notification);
 | 
			
		||||
        shown = true;
 | 
			
		||||
    }
 | 
			
		||||
		// Send the notification.
 | 
			
		||||
		//mNM.notify(NOTIFICATION, notification);
 | 
			
		||||
		startForeground(NOTIFICATION, notification);
 | 
			
		||||
		shown = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    @RequiresApi(Build.VERSION_CODES.O)
 | 
			
		||||
    private synchronized String createNotificationChannel() {
 | 
			
		||||
        String channelId = getString(R.string.app_name);
 | 
			
		||||
        CharSequence channelName = "I2Pd service";
 | 
			
		||||
        NotificationChannel chan = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_LOW);
 | 
			
		||||
        //chan.setLightColor(Color.PURPLE);
 | 
			
		||||
        chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
 | 
			
		||||
        NotificationManager service = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
 | 
			
		||||
        service.createNotificationChannel(chan);
 | 
			
		||||
        return channelId;
 | 
			
		||||
    }
 | 
			
		||||
	@RequiresApi(Build.VERSION_CODES.O)
 | 
			
		||||
	private synchronized String createNotificationChannel() {
 | 
			
		||||
		String channelId = getString(R.string.app_name);
 | 
			
		||||
		CharSequence channelName = "I2Pd service";
 | 
			
		||||
		NotificationChannel chan = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_LOW);
 | 
			
		||||
		//chan.setLightColor(Color.PURPLE);
 | 
			
		||||
		chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
 | 
			
		||||
		NotificationManager service = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
 | 
			
		||||
		service.createNotificationChannel(chan);
 | 
			
		||||
		return channelId;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    private static final DaemonSingleton daemon = DaemonSingleton.getInstance();
 | 
			
		||||
	private static final DaemonSingleton daemon = DaemonSingleton.getInstance();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -66,9 +66,9 @@ public class I2PDActivity extends Activity {
 | 
			
		|||
						}
 | 
			
		||||
						DaemonSingleton.State state = daemon.getState();
 | 
			
		||||
						textView.setText(
 | 
			
		||||
						String.valueOf(state)+
 | 
			
		||||
						(DaemonSingleton.State.startFailed.equals(state)?": "+daemon.getDaemonStartResult():"")+
 | 
			
		||||
						(DaemonSingleton.State.gracefulShutdownInProgress.equals(state)?":  "+formatGraceTimeRemaining()+" "+getText(R.string.remaining):"")
 | 
			
		||||
						String.valueOf(getText(state.getStatusStringResourceId()))+
 | 
			
		||||
						(DaemonSingleton.State.startFailed.equals(state) ? ": "+daemon.getDaemonStartResult() : "")+
 | 
			
		||||
						(DaemonSingleton.State.gracefulShutdownInProgress.equals(state) ? ":  "+formatGraceTimeRemaining()+" "+getText(R.string.remaining) : "")
 | 
			
		||||
						);
 | 
			
		||||
					} catch (Throwable tr) {
 | 
			
		||||
						Log.e(TAG,"error ignored",tr);
 | 
			
		||||
| 
						 | 
				
			
			@ -100,14 +100,14 @@ public class I2PDActivity extends Activity {
 | 
			
		|||
		daemonStateUpdatedListener.daemonStateUpdate();
 | 
			
		||||
 | 
			
		||||
		 // request permissions
 | 
			
		||||
        if (Build.VERSION.SDK_INT >= 23) 
 | 
			
		||||
		if (Build.VERSION.SDK_INT >= 23)
 | 
			
		||||
		{
 | 
			
		||||
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) 
 | 
			
		||||
			if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) 
 | 
			
		||||
			{
 | 
			
		||||
                ActivityCompat.requestPermissions(this,
 | 
			
		||||
                	new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
 | 
			
		||||
                    MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE);
 | 
			
		||||
            }
 | 
			
		||||
				ActivityCompat.requestPermissions(this,
 | 
			
		||||
					new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
 | 
			
		||||
					MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// set the app be foreground
 | 
			
		||||
| 
						 | 
				
			
			@ -139,19 +139,19 @@ public class I2PDActivity extends Activity {
 | 
			
		|||
	@Override
 | 
			
		||||
	public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) 
 | 
			
		||||
	{
 | 
			
		||||
    	switch (requestCode) 
 | 
			
		||||
		switch (requestCode) 
 | 
			
		||||
		{
 | 
			
		||||
        	case MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE:
 | 
			
		||||
			case MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE:
 | 
			
		||||
			{
 | 
			
		||||
		        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) 
 | 
			
		||||
		            Log.e(TAG, "Memory permission granted");
 | 
			
		||||
				if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) 
 | 
			
		||||
					Log.e(TAG, "Memory permission granted");
 | 
			
		||||
				else 
 | 
			
		||||
		            Log.e(TAG, "Memory permission declined");
 | 
			
		||||
					Log.e(TAG, "Memory permission declined");
 | 
			
		||||
					// TODO: terminate
 | 
			
		||||
		        return;
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
			default: ;	
 | 
			
		||||
    	}
 | 
			
		||||
			default: ;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static void cancelGracefulStop() {
 | 
			
		||||
| 
						 | 
				
			
			@ -249,7 +249,7 @@ public class I2PDActivity extends Activity {
 | 
			
		|||
				{
 | 
			
		||||
					item.setTitle(R.string.action_cancel_graceful_stop);	
 | 
			
		||||
					i2pdGracefulStop();
 | 
			
		||||
				}	
 | 
			
		||||
				}
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -329,7 +329,7 @@ public class I2PDActivity extends Activity {
 | 
			
		|||
						daemon.startAcceptingTunnels();
 | 
			
		||||
					else
 | 
			
		||||
						i2pdStop();
 | 
			
		||||
				} 
 | 
			
		||||
				}
 | 
			
		||||
				catch(Throwable tr)
 | 
			
		||||
				{
 | 
			
		||||
					Log.e(TAG,"",tr);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,157 +15,157 @@ import java.lang.reflect.Method;
 | 
			
		|||
//android.permission.WRITE_EXTERNAL_STORAGE
 | 
			
		||||
public class I2PDPermsAskerActivity extends Activity {
 | 
			
		||||
 | 
			
		||||
    private static final int PERMISSION_WRITE_EXTERNAL_STORAGE = 0;
 | 
			
		||||
	private static final int PERMISSION_WRITE_EXTERNAL_STORAGE = 0;
 | 
			
		||||
 | 
			
		||||
    private Button button_request_write_ext_storage_perms;
 | 
			
		||||
    private TextView textview_retry;
 | 
			
		||||
	private Button button_request_write_ext_storage_perms;
 | 
			
		||||
	private TextView textview_retry;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected void onCreate(Bundle savedInstanceState) {
 | 
			
		||||
        super.onCreate(savedInstanceState);
 | 
			
		||||
        //if less than Android 6, no runtime perms req system present
 | 
			
		||||
        if (android.os.Build.VERSION.SDK_INT < 23) {
 | 
			
		||||
            startMainActivity();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
	@Override
 | 
			
		||||
	protected void onCreate(Bundle savedInstanceState) {
 | 
			
		||||
		super.onCreate(savedInstanceState);
 | 
			
		||||
		//if less than Android 6, no runtime perms req system present
 | 
			
		||||
		if (android.os.Build.VERSION.SDK_INT < 23) {
 | 
			
		||||
			startMainActivity();
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        setContentView(R.layout.activity_perms_asker);
 | 
			
		||||
        button_request_write_ext_storage_perms = (Button) findViewById(R.id.button_request_write_ext_storage_perms);
 | 
			
		||||
        textview_retry = (TextView) findViewById(R.id.textview_retry);
 | 
			
		||||
		setContentView(R.layout.activity_perms_asker);
 | 
			
		||||
		button_request_write_ext_storage_perms = (Button) findViewById(R.id.button_request_write_ext_storage_perms);
 | 
			
		||||
		textview_retry = (TextView) findViewById(R.id.textview_retry);
 | 
			
		||||
 | 
			
		||||
        button_request_write_ext_storage_perms.setOnClickListener(new View.OnClickListener() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onClick(View view) {
 | 
			
		||||
                request_write_ext_storage_perms();
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        request_write_ext_storage_perms();
 | 
			
		||||
    }
 | 
			
		||||
		button_request_write_ext_storage_perms.setOnClickListener(new View.OnClickListener() {
 | 
			
		||||
			@Override
 | 
			
		||||
			public void onClick(View view) {
 | 
			
		||||
				request_write_ext_storage_perms();
 | 
			
		||||
			}
 | 
			
		||||
		});
 | 
			
		||||
		request_write_ext_storage_perms();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    private void request_write_ext_storage_perms() {
 | 
			
		||||
	private void request_write_ext_storage_perms() {
 | 
			
		||||
 | 
			
		||||
        textview_retry.setVisibility(TextView.GONE);
 | 
			
		||||
        button_request_write_ext_storage_perms.setVisibility(Button.GONE);
 | 
			
		||||
		textview_retry.setVisibility(TextView.GONE);
 | 
			
		||||
		button_request_write_ext_storage_perms.setVisibility(Button.GONE);
 | 
			
		||||
 | 
			
		||||
        Method methodCheckPermission;
 | 
			
		||||
        Method method_shouldShowRequestPermissionRationale;
 | 
			
		||||
        Method method_requestPermissions;
 | 
			
		||||
        try {
 | 
			
		||||
            methodCheckPermission = getClass().getMethod("checkSelfPermission", String.class);
 | 
			
		||||
            method_shouldShowRequestPermissionRationale =
 | 
			
		||||
                    getClass().getMethod("shouldShowRequestPermissionRationale", String.class);
 | 
			
		||||
            method_requestPermissions =
 | 
			
		||||
                    getClass().getMethod("requestPermissions", String[].class, int.class);
 | 
			
		||||
        } catch (NoSuchMethodException e) {
 | 
			
		||||
            throw new RuntimeException(e);
 | 
			
		||||
        }
 | 
			
		||||
        Integer resultObj;
 | 
			
		||||
        try {
 | 
			
		||||
            resultObj = (Integer) methodCheckPermission.invoke(
 | 
			
		||||
                    this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
 | 
			
		||||
        } catch (Throwable e) {
 | 
			
		||||
            throw new RuntimeException(e);
 | 
			
		||||
        }
 | 
			
		||||
		Method methodCheckPermission;
 | 
			
		||||
		Method method_shouldShowRequestPermissionRationale;
 | 
			
		||||
		Method method_requestPermissions;
 | 
			
		||||
		try {
 | 
			
		||||
			methodCheckPermission = getClass().getMethod("checkSelfPermission", String.class);
 | 
			
		||||
			method_shouldShowRequestPermissionRationale =
 | 
			
		||||
					getClass().getMethod("shouldShowRequestPermissionRationale", String.class);
 | 
			
		||||
			method_requestPermissions =
 | 
			
		||||
					getClass().getMethod("requestPermissions", String[].class, int.class);
 | 
			
		||||
		} catch (NoSuchMethodException e) {
 | 
			
		||||
			throw new RuntimeException(e);
 | 
			
		||||
		}
 | 
			
		||||
		Integer resultObj;
 | 
			
		||||
		try {
 | 
			
		||||
			resultObj = (Integer) methodCheckPermission.invoke(
 | 
			
		||||
					this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
 | 
			
		||||
		} catch (Throwable e) {
 | 
			
		||||
			throw new RuntimeException(e);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
        if (resultObj != PackageManager.PERMISSION_GRANTED) {
 | 
			
		||||
		if (resultObj != PackageManager.PERMISSION_GRANTED) {
 | 
			
		||||
 | 
			
		||||
            // Should we show an explanation?
 | 
			
		||||
            Boolean aBoolean;
 | 
			
		||||
            try {
 | 
			
		||||
                aBoolean = (Boolean) method_shouldShowRequestPermissionRationale.invoke(this,
 | 
			
		||||
                        Manifest.permission.WRITE_EXTERNAL_STORAGE);
 | 
			
		||||
            } catch (Exception e) {
 | 
			
		||||
                throw new RuntimeException(e);
 | 
			
		||||
            }
 | 
			
		||||
            if (aBoolean) {
 | 
			
		||||
			// Should we show an explanation?
 | 
			
		||||
			Boolean aBoolean;
 | 
			
		||||
			try {
 | 
			
		||||
				aBoolean = (Boolean) method_shouldShowRequestPermissionRationale.invoke(this,
 | 
			
		||||
						Manifest.permission.WRITE_EXTERNAL_STORAGE);
 | 
			
		||||
			} catch (Exception e) {
 | 
			
		||||
				throw new RuntimeException(e);
 | 
			
		||||
			}
 | 
			
		||||
			if (aBoolean) {
 | 
			
		||||
 | 
			
		||||
                // Show an explanation to the user *asynchronously* -- don't block
 | 
			
		||||
                // this thread waiting for the user's response! After the user
 | 
			
		||||
                // sees the explanation, try again to request the permission.
 | 
			
		||||
				// Show an explanation to the user *asynchronously* -- don't block
 | 
			
		||||
				// this thread waiting for the user's response! After the user
 | 
			
		||||
				// sees the explanation, try again to request the permission.
 | 
			
		||||
 | 
			
		||||
                showExplanation();
 | 
			
		||||
				showExplanation();
 | 
			
		||||
 | 
			
		||||
            } else {
 | 
			
		||||
			} else {
 | 
			
		||||
 | 
			
		||||
                // No explanation needed, we can request the permission.
 | 
			
		||||
				// No explanation needed, we can request the permission.
 | 
			
		||||
 | 
			
		||||
                try {
 | 
			
		||||
                    method_requestPermissions.invoke(this,
 | 
			
		||||
                            new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
 | 
			
		||||
                            PERMISSION_WRITE_EXTERNAL_STORAGE);
 | 
			
		||||
                } catch (Exception e) {
 | 
			
		||||
                    throw new RuntimeException(e);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } else startMainActivity();
 | 
			
		||||
    }
 | 
			
		||||
				try {
 | 
			
		||||
					method_requestPermissions.invoke(this,
 | 
			
		||||
							new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
 | 
			
		||||
							PERMISSION_WRITE_EXTERNAL_STORAGE);
 | 
			
		||||
				} catch (Exception e) {
 | 
			
		||||
					throw new RuntimeException(e);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		} else startMainActivity();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onRequestPermissionsResult(int requestCode,
 | 
			
		||||
                                           String permissions[], int[] grantResults) {
 | 
			
		||||
        switch (requestCode) {
 | 
			
		||||
            case PERMISSION_WRITE_EXTERNAL_STORAGE: {
 | 
			
		||||
                // If request is cancelled, the result arrays are empty.
 | 
			
		||||
                if (grantResults.length > 0
 | 
			
		||||
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
 | 
			
		||||
	@Override
 | 
			
		||||
	public void onRequestPermissionsResult(int requestCode,
 | 
			
		||||
		String permissions[], int[] grantResults) {
 | 
			
		||||
		switch (requestCode) {
 | 
			
		||||
			case PERMISSION_WRITE_EXTERNAL_STORAGE: {
 | 
			
		||||
				// If request is cancelled, the result arrays are empty.
 | 
			
		||||
				if (grantResults.length > 0
 | 
			
		||||
						&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
 | 
			
		||||
 | 
			
		||||
                    // permission was granted, yay! Do the
 | 
			
		||||
                    // contacts-related task you need to do.
 | 
			
		||||
					// permission was granted, yay! Do the
 | 
			
		||||
					// contacts-related task you need to do.
 | 
			
		||||
 | 
			
		||||
                    startMainActivity();
 | 
			
		||||
					startMainActivity();
 | 
			
		||||
 | 
			
		||||
                } else {
 | 
			
		||||
				} else {
 | 
			
		||||
 | 
			
		||||
                    // permission denied, boo! Disable the
 | 
			
		||||
                    // functionality that depends on this permission.
 | 
			
		||||
                    textview_retry.setText("SD card write permission denied, you need to allow this to continue");
 | 
			
		||||
                    textview_retry.setVisibility(TextView.VISIBLE);
 | 
			
		||||
                    button_request_write_ext_storage_perms.setVisibility(Button.VISIBLE);
 | 
			
		||||
                }
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
					// permission denied, boo! Disable the
 | 
			
		||||
					// functionality that depends on this permission.
 | 
			
		||||
					textview_retry.setText("SD card write permission denied, you need to allow this to continue");
 | 
			
		||||
					textview_retry.setVisibility(TextView.VISIBLE);
 | 
			
		||||
					button_request_write_ext_storage_perms.setVisibility(Button.VISIBLE);
 | 
			
		||||
				}
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
            // other 'case' lines to check for other
 | 
			
		||||
            // permissions this app might request.
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
			// other 'case' lines to check for other
 | 
			
		||||
			// permissions this app might request.
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    private void startMainActivity() {
 | 
			
		||||
        startActivity(new Intent(this, I2PDActivity.class));
 | 
			
		||||
        finish();
 | 
			
		||||
    }
 | 
			
		||||
	private void startMainActivity() {
 | 
			
		||||
		startActivity(new Intent(this, I2PDActivity.class));
 | 
			
		||||
		finish();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    private static final int SHOW_EXPLANATION_REQUEST = 1;  // The request code
 | 
			
		||||
    private void showExplanation() {
 | 
			
		||||
        Intent intent = new Intent(this, I2PDPermsExplanationActivity.class);
 | 
			
		||||
        startActivityForResult(intent, SHOW_EXPLANATION_REQUEST);
 | 
			
		||||
    }
 | 
			
		||||
	private static final int SHOW_EXPLANATION_REQUEST = 1;  // The request code
 | 
			
		||||
	private void showExplanation() {
 | 
			
		||||
		Intent intent = new Intent(this, I2PDPermsExplanationActivity.class);
 | 
			
		||||
		startActivityForResult(intent, SHOW_EXPLANATION_REQUEST);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
 | 
			
		||||
        // Check which request we're responding to
 | 
			
		||||
        if (requestCode == SHOW_EXPLANATION_REQUEST) {
 | 
			
		||||
            // Make sure the request was successful
 | 
			
		||||
            if (resultCode == RESULT_OK) {
 | 
			
		||||
                // Request the permission
 | 
			
		||||
                Method method_requestPermissions;
 | 
			
		||||
                try {
 | 
			
		||||
                    method_requestPermissions =
 | 
			
		||||
                            getClass().getMethod("requestPermissions", String[].class, int.class);
 | 
			
		||||
                } catch (NoSuchMethodException e) {
 | 
			
		||||
                    throw new RuntimeException(e);
 | 
			
		||||
                }
 | 
			
		||||
                try {
 | 
			
		||||
                    method_requestPermissions.invoke(this,
 | 
			
		||||
                            new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
 | 
			
		||||
                            PERMISSION_WRITE_EXTERNAL_STORAGE);
 | 
			
		||||
                } catch (Exception e) {
 | 
			
		||||
                    throw new RuntimeException(e);
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                finish(); //close the app
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
	@Override
 | 
			
		||||
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
 | 
			
		||||
		// Check which request we're responding to
 | 
			
		||||
		if (requestCode == SHOW_EXPLANATION_REQUEST) {
 | 
			
		||||
			// Make sure the request was successful
 | 
			
		||||
			if (resultCode == RESULT_OK) {
 | 
			
		||||
				// Request the permission
 | 
			
		||||
				Method method_requestPermissions;
 | 
			
		||||
				try {
 | 
			
		||||
					method_requestPermissions =
 | 
			
		||||
							getClass().getMethod("requestPermissions", String[].class, int.class);
 | 
			
		||||
				} catch (NoSuchMethodException e) {
 | 
			
		||||
					throw new RuntimeException(e);
 | 
			
		||||
				}
 | 
			
		||||
				try {
 | 
			
		||||
					method_requestPermissions.invoke(this,
 | 
			
		||||
							new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
 | 
			
		||||
							PERMISSION_WRITE_EXTERNAL_STORAGE);
 | 
			
		||||
				} catch (Exception e) {
 | 
			
		||||
					throw new RuntimeException(e);
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				finish(); //close the app
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,30 +9,30 @@ import android.widget.Button;
 | 
			
		|||
 | 
			
		||||
public class I2PDPermsExplanationActivity extends Activity {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected void onCreate(Bundle savedInstanceState) {
 | 
			
		||||
        super.onCreate(savedInstanceState);
 | 
			
		||||
        setContentView(R.layout.activity_perms_explanation);
 | 
			
		||||
        ActionBar actionBar = getActionBar();
 | 
			
		||||
        if(actionBar!=null)actionBar.setHomeButtonEnabled(false);
 | 
			
		||||
        Button button_ok = (Button) findViewById(R.id.button_ok);
 | 
			
		||||
        button_ok.setOnClickListener(new View.OnClickListener() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onClick(View view) {
 | 
			
		||||
                returnFromActivity();
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
	@Override
 | 
			
		||||
	protected void onCreate(Bundle savedInstanceState) {
 | 
			
		||||
		super.onCreate(savedInstanceState);
 | 
			
		||||
		setContentView(R.layout.activity_perms_explanation);
 | 
			
		||||
		ActionBar actionBar = getActionBar();
 | 
			
		||||
		if(actionBar!=null)actionBar.setHomeButtonEnabled(false);
 | 
			
		||||
		Button button_ok = (Button) findViewById(R.id.button_ok);
 | 
			
		||||
		button_ok.setOnClickListener(new View.OnClickListener() {
 | 
			
		||||
			@Override
 | 
			
		||||
			public void onClick(View view) {
 | 
			
		||||
				returnFromActivity();
 | 
			
		||||
			}
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    private void returnFromActivity() {
 | 
			
		||||
        Intent data = new Intent();
 | 
			
		||||
        Activity parent = getParent();
 | 
			
		||||
        if (parent == null) {
 | 
			
		||||
            setResult(Activity.RESULT_OK, data);
 | 
			
		||||
        } else {
 | 
			
		||||
            parent.setResult(Activity.RESULT_OK, data);
 | 
			
		||||
        }
 | 
			
		||||
        finish();
 | 
			
		||||
    }
 | 
			
		||||
	private void returnFromActivity() {
 | 
			
		||||
		Intent data = new Intent();
 | 
			
		||||
		Activity parent = getParent();
 | 
			
		||||
		if (parent == null) {
 | 
			
		||||
			setResult(Activity.RESULT_OK, data);
 | 
			
		||||
		} else {
 | 
			
		||||
			parent.setResult(Activity.RESULT_OK, data);
 | 
			
		||||
		}
 | 
			
		||||
		finish();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,23 +1,25 @@
 | 
			
		|||
package org.purplei2p.i2pd;
 | 
			
		||||
 | 
			
		||||
public class I2PD_JNI {
 | 
			
		||||
    public static native String getABICompiledWith();
 | 
			
		||||
	public static native String getABICompiledWith();
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * returns error info if failed
 | 
			
		||||
	 * returns "ok" if daemon initialized and started okay
 | 
			
		||||
	 */
 | 
			
		||||
    public static native String startDaemon();
 | 
			
		||||
    //should only be called after startDaemon() success
 | 
			
		||||
    public static native void stopDaemon();
 | 
			
		||||
	public static native String startDaemon();
 | 
			
		||||
 | 
			
		||||
    public static native void stopAcceptingTunnels();
 | 
			
		||||
	//should only be called after startDaemon() success
 | 
			
		||||
	public static native void stopDaemon();
 | 
			
		||||
 | 
			
		||||
	public static native void stopAcceptingTunnels();
 | 
			
		||||
 | 
			
		||||
	public static native void startAcceptingTunnels();
 | 
			
		||||
 | 
			
		||||
	public static native void onNetworkStateChanged(boolean isConnected);
 | 
			
		||||
 | 
			
		||||
	public static void loadLibraries() {
 | 
			
		||||
    	System.loadLibrary("c++_shared");
 | 
			
		||||
        System.loadLibrary("i2pd");
 | 
			
		||||
    }
 | 
			
		||||
		//System.loadLibrary("c++_shared");
 | 
			
		||||
		System.loadLibrary("i2pd");
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,12 +9,12 @@ import android.net.NetworkInfo;
 | 
			
		|||
 | 
			
		||||
public class NetworkStateChangeReceiver extends BroadcastReceiver {
 | 
			
		||||
 | 
			
		||||
    private static final String TAG = "i2pd";
 | 
			
		||||
	private static final String TAG = "i2pd";
 | 
			
		||||
 | 
			
		||||
	//api level 1
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onReceive(final Context context, final Intent intent) {
 | 
			
		||||
        Log.d(TAG,"Network state change");
 | 
			
		||||
	@Override
 | 
			
		||||
	public void onReceive(final Context context, final Intent intent) {
 | 
			
		||||
		Log.d(TAG,"Network state change");
 | 
			
		||||
		try {
 | 
			
		||||
			ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
 | 
			
		||||
			NetworkInfo activeNetworkInfo = cm.getActiveNetworkInfo();
 | 
			
		||||
| 
						 | 
				
			
			@ -26,5 +26,5 @@ public class NetworkStateChangeReceiver extends BroadcastReceiver {
 | 
			
		|||
		} catch (Throwable tr) {
 | 
			
		||||
			Log.d(TAG,"",tr);
 | 
			
		||||
		}
 | 
			
		||||
    }
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue