<repo_name>eastar-dev/EastarOperaXInterceptor<file_sep>/operaxinterceptor/src/androidTest/java/dev/eastar/operaxinterceptor/event/OperaXEventTestKt.kt
package dev.eastar.operaxinterceptor.event

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import dev.eastar.operaxinterceptor.event.OperaXEventObservable.notify
import org.junit.Assert
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class OperaXEventTestKt {
    @Test
    fun useAppContext() {
        val appContext = InstrumentationRegistry.getInstrumentation().targetContext
        Assert.assertEquals("dev.eastar.operaxinterceptor", appContext.packageName)
    }

    @Test
    fun sendTest() {
        notify(OperaXEvents.Exited)
    }
}<file_sep>/operaxinterceptor/src/main/java/dev/eastar/operaxinterceptor/interceptor/OperaXInterceptor.kt
/*
 * Copyright 2019 copyright <NAME>
 *
 * 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 dev.eastar.operaxinterceptor.interceptor

import android.app.Activity
import java.util.*

abstract class OperaXInterceptor : OperaXInitializer(), Observer {
    override fun onCreate(): Boolean {
        super.onCreate()
        OperaXInterceptorObserver.addObserver(this)
        android.util.Log.d("OperaXInterceptor", javaClass.name)
        return true
    }

    override fun update(observable: Observable, data: Any) {
        if ((data as Type).activity.javaClass.getAnnotation(OperaXSkip::class.java) != null) {
            return
        }

        try {
            when (data) {
                is ON_CREATE -> onCreate(data.activity)
                is ON_DESTROY -> onDestroy(data.activity)
                is ON_START -> onStart(data.activity)
                is ON_STOP -> onStop(data.activity)
                is ON_RESUME -> onResume(data.activity)
                is ON_PAUSE -> onPause(data.activity)
                else -> Unit //Log.e("!undefined message")
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    protected open fun onCreate(activity: Activity) {}
    protected open fun onDestroy(activity: Activity) {}
    protected open fun onStart(activity: Activity) {}
    protected open fun onStop(activity: Activity) {}
    protected open fun onResume(activity: Activity) {}
    protected open fun onPause(activity: Activity) {}

    @Target(AnnotationTarget.CLASS)
    @Retention(AnnotationRetention.RUNTIME)
    @MustBeDocumented
    annotation class OperaXMain

    @Target(AnnotationTarget.CLASS)
    @Retention(AnnotationRetention.RUNTIME)
    @MustBeDocumented
    annotation class OperaXSkip
}

<file_sep>/operaxinterceptor/src/main/java/dev/eastar/operaxinterceptor/event/OperaXEventInitializer.kt
/*
 * Copyright 2019 copyright <NAME>
 *
 * 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 dev.eastar.operaxinterceptor.event

import android.app.Activity
import android.app.Application
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks
import dev.eastar.operaxinterceptor.interceptor.OperaXInitializer

class OperaXEventInitializer : OperaXInitializer() {
    override fun initialize(application: Application) {
        application.operaXEventRegister()
    }
}

fun Application.operaXEventRegister() {
    registerActivityLifecycleCallbacks(
            object : Application.ActivityLifecycleCallbacks {
                override fun onActivityCreated(activity: Activity, bundle: Bundle?) {
                    if (activity is OperaXEventObserver) OperaXEventObservable.addObserver(activity)
                    if (activity is AppCompatActivity) registerFragment(activity)
                }

                override fun onActivityDestroyed(activity: Activity) {
                    if (activity is OperaXEventObserver) OperaXEventObservable.deleteObserver(activity)
                }


                fun registerFragment(activity: AppCompatActivity) {
                    activity.supportFragmentManager.registerFragmentLifecycleCallbacks(object : FragmentLifecycleCallbacks() {
                        override fun onFragmentCreated(fm: FragmentManager, f: Fragment, savedInstanceState: Bundle?) {
                            if (f is OperaXEventObserver) OperaXEventObservable.addObserver(f)
                        }

                        override fun onFragmentDestroyed(fm: FragmentManager, f: Fragment) {
                            if (f is OperaXEventObserver) OperaXEventObservable.deleteObserver(f)
                        }
                    }, true)
                }

                override fun onActivityStarted(activity: Activity) {}
                override fun onActivityStopped(activity: Activity) {}
                override fun onActivityResumed(activity: Activity) {}
                override fun onActivityPaused(activity: Activity) {}
                override fun onActivitySaveInstanceState(activity: Activity, bundle: Bundle) {}
            }
    )
}





<file_sep>/operaxinterceptor/src/debug/java/opera/OperaXInterceptorDump.kt
package opera

import android.app.Application
import dalvik.system.DexFile
import dev.eastar.operaxinterceptor.interceptor.OperaXInterceptor
import java.util.concurrent.Executors

fun Application.operaXInterceptorDump() {
    Executors.newSingleThreadExecutor().execute {
        runCatching {
            val parentClass = OperaXInterceptor::class.java
            val packageName = parentClass.`package`?.name!!
            val thisClass = parentClass.name
            DexFile(packageCodePath).entries().toList()
                    .filter { it.startsWith(packageName) }
                    .filterNot { it.startsWith(thisClass) }
                    .filterNot { it.contains('$') }
                    .map { Class.forName(it) }
                    .filter { parentClass.isAssignableFrom(it) }
                    .forEach { android.util.Log.w("OperaXInterceptorDump", it.toString()) }
        }
    }
}<file_sep>/operaxinterceptor/src/main/java/dev/eastar/operaxinterceptor/event/OperaXEventObservable.kt
/*
 * Copyright 2019 copyright <NAME>
 *
 * 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 dev.eastar.operaxinterceptor.event

import androidx.annotation.MainThread
import java.util.*

object OperaXEventObservable : Observable() {
    @MainThread
    @JvmStatic
    fun notify(obj: Any) {
        notifyObservers(obj)
    }

    override fun notifyObservers(data: Any) {
        if (data.javaClass.getAnnotation(OperaXEvent::class.java) == null)
            throw UnsupportedOperationException("!event obj must annotation in the ${OperaXEvent::class.java}")

        setChanged()
        super.notifyObservers(data)
    }
}
<file_sep>/operaxinterceptor/src/main/java/dev/eastar/operaxinterceptor/event/OperaXEvent.kt
package dev.eastar.operaxinterceptor.event

@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class OperaXEvent
<file_sep>/operaxinterceptor/src/main/java/dev/eastar/operaxinterceptor/event/OperaXEvents.kt
package dev.eastar.operaxinterceptor.event

@OperaXEvent
enum class OperaXEvents {
    Exited, Logouted, Logined;
}

<file_sep>/settings.gradle
include ':operaxinterceptor'

<file_sep>/operaxinterceptor/src/main/java/dev/eastar/operaxinterceptor/interceptor/OperaXInitializer.kt
/*
 * Copyright 2019 copyright <NAME>
 *
 * 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 dev.eastar.operaxinterceptor.interceptor

import android.app.Application
import android.content.ContentProvider
import android.content.ContentValues
import android.database.Cursor
import android.net.Uri

abstract class OperaXInitializer : ContentProvider() {
    abstract fun initialize(application: Application)

    override fun onCreate(): Boolean {
        (context?.applicationContext as? Application)?.let {
            android.util.Log.d("OperaXInitializer", javaClass.name);
            initialize(it)
        }
        return true
    }

    override fun getType(uri: Uri): String? = null
    override fun insert(uri: Uri, values: ContentValues?): Uri? = null
    override fun query(uri: Uri, projection: Array<String>?, selection: String?, selectionArgs: Array<String>?, sortOrder: String?): Cursor? = null
    override fun update(uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array<String>?): Int = 0
    override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int = 0
}
