Cannot access 'TAG': it is invisible (private in supertype) in 'AppCompatActivity' - android-activity

I am a beginner in android programming. I'm currently using android studio 3.2.1.
I am trying to monitor the different states of an android activity in log. I have written the code shown below, but I keep receiving the error message:
Cannot access 'TAG': it is invisible (private in supertype) in 'AppCompatActivity'.
Even after searching, I cannot figure the error. Can some one help?
Code:
package com.cooperation.bestech.test1
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.util.Log;
class MainActivity : AppCompatActivity() {
private static final String TAG = "MyMessage";
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Log.i(TAG, "onCreate");
}
override fun onStart() {
super.onStart()
Log.i(TAG, "onStart");
}
override fun onPause() {
super.onPause()
Log.i(TAG, "onPause");
}
override fun onResume() {
super.onResume()
Log.i(TAG, "onResume");
}
override fun onStop() {
super.onStop()
Log.i(TAG, "onStop");
}
override fun onRestart() {
super.onRestart()
Log.i(TAG, "onRestart");
}
override fun onDestroy() {
super.onDestroy()
Log.i(TAG, "onDestroy");
}
override fun onSaveInstanceState(outState: Bundle?) {
super.onSaveInstanceState(outState)
Log.i(TAG, "onSaveInstanceState");
}
override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
super.onRestoreInstanceState(savedInstanceState)
Log.i(TAG, "onRestoreInstanceState");
}
}

Since the original question is written in Kotlin (from comment), ignore the request of "launch Java project instead of the default Kotlin" may be a better solution.
And, applying the correct way to declare and assign a variable, your code segment should be like this:
class MainActivity : AppCompatActivity() {
val TAG = "MyMessage"

import android.content.ContentValues.TAG

Seems you are using Kotlin.So you need to define TAG in kotlin way:
In Kotlin constants located in the companion object:
class MyClass {
companion object {
private val TAG = "ClassName"
}
}

Related

Implementing a flutter plugin to wake screen when app is asleep

I am trying to turn on a screen once an alarm fires. I am using this
[package][1] for the alarm. However, after time doing research I have not come any closer to achieving waking the screen on alarm firing.
The solutions either use deprecated APIs or are only specific to code within some contexts like activities and fragments, which is not the case for a flutter plugin.
Here is what I have tried
-Implementing ActivityAware interface but the onAttachedToActivity() never seems to fire
-Changing activity settings of my main activity in android manifes
android:showWhenLocked="true"
android:turnScreenOn="true"
I am currently trying to get an activity within the plugin to add flags to it to turn the screen on
if (Build.VERSION.SDK_INT < 27)
activity!!.window.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON)
else
activity!!.setTurnScreenOn(true)
The problem is the activity variable is always null because for some reason, onAttachedToActivity doesn't run.
I have created an activity within the native code but I don't know how to get a reference to that activity and use it to turn the flags on. Remember, my screen is turned off so this is possibly what is complicating the matter.
Here is where I create the activity:
private fun startMainActivity(context: Context) {
val pm = context.packageManager
val intent = pm.getLaunchIntentForPackage(context.packageName)
context.startActivity(intent)
turnScreenON()
}
How can I create this plugin to wake the screen when an alarm fires?
Here is my code for the android kotlin side:
package com.example.wake_screen
import android.app.Activity
import android.content.Context
import android.os.Build
import android.util.Log
import android.view.WindowManager
import androidx.annotation.NonNull
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
/** WakeScreenPlugin */
class WakeScreenPlugin: ActivityAware, FlutterPlugin, MethodCallHandler{
private lateinit var channel : MethodChannel
private lateinit var mContext: Context
private var activity: Activity? = null
override fun onAttachedToEngine(#NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "wake_screen")
channel.setMethodCallHandler(this)
mContext = flutterPluginBinding.applicationContext
}
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
activity = binding.activity
Log.d("We are attached",binding.lifecycle.toString())
}
override fun onDetachedFromActivity() {
//release resources
}
override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
activity = binding.activity
}
override fun onDetachedFromActivityForConfigChanges() {
//release resources
}
override fun onMethodCall(#NonNull call: MethodCall, #NonNull result: Result) {
if (call.method == "getPlatformVersion") {
startMainActivity(mContext)
result.success("Android ${android.os.Build.VERSION.RELEASE}")
}
else {
result.notImplemented()
}
}
private fun turnScreenON(){
if (Build.VERSION.SDK_INT < 27)
activity!!.window.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON)
else
activity!!.setTurnScreenOn(true)
}
private fun startMainActivity(context: Context) {
val pm = context.packageManager
val intent = pm.getLaunchIntentForPackage(context.packageName)
context.startActivity(intent)
turnScreenON()
}
override fun onDetachedFromEngine(#NonNull binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)
}
}
Here's my code on the flutter side:
//Provide instruction to wake device after duration
void setAlarm() async {
await AndroidAlarmManager.oneShot(
const Duration(seconds: _duration),
0,
wakeTheScreen,
wakeup: true,
allowWhileIdle: true,
);
}
//Function invoking platform code
static Future<void> wakeTheScreen() async {
String? version = await WakeScreen().getPlatformVersion();
print(version);
}
In summary, How do I wake the screen up using a flutter plugin that needs an activity to work
[1]: https://pub.dev/packages/android_alarm_manager_plus

How to make a FlutterActivity be a MethodCallHandler?

I made my FlutterActivity MainActivity a MethodCallHandler:
class MainActivity: FlutterActivity(), MethodCallHandler {
so I implemented onMethodCall.
However, to be able to process method calls, still something is missing. This is how it's done in a Flutter plugin:
class MyPlugin: FlutterPlugin {
private lateinit var channel : MethodChannel
private val LOG_TAG: String = "MyPlugin.kt"
override fun onAttachedToEngine(#NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "myplugin")
channel.setMethodCallHandler(this)
}
How can I make my MainActivity be the actual MethodCallHandler?
configureFlutterEngine provides binding between Dart and native.
class MainActivity: FlutterActivity() {
override fun configureFlutterEngine(#NonNull flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "<your_channel>").setMethodCallHandler {
call, result ->
// TODO
}
}
...

Having trouble figuring out how to place code into kotlin and use a method channel to send functions from flutter

My MainActivity.kt:
class MainActivity : FlutterActivity() {
private val CHANNEL = "flutter.native/helper"
private var mapId: Int? = null
override fun onCreate(savedInstanceState: Bundle?, PersistentState: PersistableBundle?) {
super.onCreate(savedInstanceState, PersistentState)
GeneratedPluginRegistrant.registerWith(FlutterEngine(this));
}
override fun configureFlutterEngine(#NonNull flutterEngine: FlutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine);
MethodChannel(flutterEngine.dartExecutor, CHANNEL).setMethodCallHandler { call, result ->
if (call.method == "KML") {
result.success(getKMLResource());
} else {
result.notImplemented();
}
}
}
private fun getKMLResource(): Int {
return R.raw.borders;
}
}
I'm trying to insert the below call, but I get a errors every time.
override fun onMethodCall(call: MethodCall, result: Result) {
when (call.method) {
"showToast" -> {
val text = call.argument<String>("text") // hello world
showToast(text)
}
}
}
Errors:
'onMethodCall' overrides nothing
One type argument expected for class Result<out T>
Unresolved reference: showToast
Here's my flutter portion:
Future<void> printSomething(GoogleMapController mapController) async {
const MethodChannel channel = MethodChannel('flutter.native/helper');
channel.invokeMethod('showToast', {'text': 'hello world'});
}
I have no idea how to incorporate this into my kotlin code properly, and there aren't many examples out there. At least none that I could find. My ultimate goal is to be able to manipulate private fun getKMLResource() and set return as a directory I select from my flutter app.
Anybody know how to do this? Please help. Thank you.
Here's my add kml flutter function:
Here's how I select my .kml:
Future<void> addKml(GoogleMapController mapController) async {
const MethodChannel channel = MethodChannel('flutter.native/helper');
try {
int kmlResourceId = await channel.invokeMethod('KML');
return mapController.channel.invokeMethod("map#addKML", <String, dynamic>{
'resourceId': kmlResourceId,
});
} on PlatformException catch (e) {
throw 'Unable to plot map: ${e.message}';
}
}
First of all, you gotta follow these documentations:
Writing custom platform-specific code
Supporting the new Android plugins APIs
Error:
'onMethodCall' overrides nothing
Means that you are trying override something that does not exist
In this situation, you have to implement missing classes that are found in the docs tutorial:
ActivityAware, FlutterPlugin, MethodChannel.MethodCallHandler
On:
MethodChannel.MethodCallHandler
You can override (Kotlin snippet):
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result)
That should fix your problem.
ActivityAware and FlutterPlugin are essentials for the new flutter upgrades and you can efficiently fix memory leaks with them.
class BubbleOverlayPlugin : ActivityAware, FlutterPlugin, MethodChannel.MethodCallHandler {
private var activity: Activity? = null
private var channel: MethodChannel? = null
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
when (call.method) {
//here lies the platform methods calls
}
}
override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
channel?.setMethodCallHandler(null)
//release resources
}
override fun onAttachedToEngine(#NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
channel = MethodChannel(flutterPluginBinding.binaryMessenger, channelName)
channel?.setMethodCallHandler(this)
}
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
activity = binding.activity
}
override fun onDetachedFromActivity() {
//release resources
}
override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
activity = binding.activity
}
override fun onDetachedFromActivityForConfigChanges() {
//release resources
}
}
You can check my source code from the plugin bubble_overlay, It is using the last docs recommendations.
Repo: bubble_overlay repo

ViewModel Junit Test fails in case when i use Junit5 and Rxjava. Method getMainLooper in android.os.Looper not mocked

I am trying to wrote test case for my view model and I am using junit5 along with mockito. The issue is my test case is always failing it gives me this error
at android.os.Looper.getMainLooper(Looper.java)
at io.reactivex.android.schedulers.AndroidSchedulers$MainHolder.<clinit>
Now I did a lot of research on this issue and found out that this is due to Rxjava scheduler as it is not able to run on the background thread I followed this link and did the required step so after that my view model looks like this
MainViewModelTest.kt
#ExtendWith(value = [InstantExecutorExtension::class,TestSchedulerExtension::class])
class MainViewModelTest {
#Mock
private lateinit var repository: GithubRepository
private lateinit var viewModel: MainViewModel
#Before
fun init() {
MockitoAnnotations.initMocks(this)
viewModel = MainViewModel(repository)
}
#Test
fun testNull(){
assertThat(viewModel.observeTrendingRepository(), notNullValue())
verify(repository, never()).makeRequestForTrendingRepo(anyBoolean())
}
#Test
fun fetchTrendingGitHubRepository_emptyDbFirstTimeCase(){
`when`(repository.makeRequestForTrendingRepo(anyBoolean()))
.thenReturn(Flowable.just(Resource.Loading(listOf())))
viewModel.fetchTrendingGitHubRepository(false) // this is where it fails
assertEquals(Resource.Loading<List<Repository>>(listOf()),LiveDataTestUtil.getValue(viewModel.observeTrendingRepository()));
}
}
Here are the InstantExecutorExtension and TestSchedulerExtension that take care of live data and Rxjava respectively.
package com.rajat.zomatotest.utils
import androidx.arch.core.executor.ArchTaskExecutor
import androidx.arch.core.executor.TaskExecutor
import org.junit.jupiter.api.extension.AfterEachCallback
import org.junit.jupiter.api.extension.BeforeEachCallback
import org.junit.jupiter.api.extension.ExtensionContext
class InstantExecutorExtension : BeforeEachCallback, AfterEachCallback {
override fun beforeEach(context: ExtensionContext?) {
ArchTaskExecutor.getInstance().setDelegate(object : TaskExecutor() {
override fun executeOnDiskIO(runnable: Runnable) {
runnable.run()
}
override fun postToMainThread(runnable: Runnable) {
runnable.run()
}
override fun isMainThread(): Boolean {
return true
}
})
}
override fun afterEach(context: ExtensionContext?) {
ArchTaskExecutor.getInstance().setDelegate(null)
}
}
package com.rajat.zomatotest.utils
import io.reactivex.android.plugins.RxAndroidPlugins
import io.reactivex.plugins.RxJavaPlugins
import io.reactivex.schedulers.Schedulers
import org.junit.jupiter.api.extension.AfterTestExecutionCallback
import org.junit.jupiter.api.extension.BeforeTestExecutionCallback
import org.junit.jupiter.api.extension.ExtensionContext
class TestSchedulerExtension : BeforeTestExecutionCallback, AfterTestExecutionCallback {
override fun beforeTestExecution(context: ExtensionContext?) {
RxJavaPlugins.setIoSchedulerHandler { Schedulers.trampoline() }
RxJavaPlugins.setComputationSchedulerHandler { Schedulers.trampoline() }
RxJavaPlugins.setNewThreadSchedulerHandler { Schedulers.trampoline() }
RxAndroidPlugins.setMainThreadSchedulerHandler { Schedulers.trampoline() }
}
override fun afterTestExecution(context: ExtensionContext?) {
RxJavaPlugins.reset()
RxAndroidPlugins.reset()
}
}
I couldn't understand why is it giving me error, I have correctly added TestSchedulerExtension.kt so this should work!!
I run into the same problem, and I found that the way to fix this was by using
RxAndroidPlugins.setInitMainThreadSchedulerHandler { scheduler }
instead of
RxAndroidPlugins.setMainThreadSchedulerHandler { scheduler }
In this link you will find more information.

Dagger can not inject ViewModel with KClass

I am moving my project java to kotlin, but got some confusion about KClass and Class
Here is my BaseActivity
abstract class BaseActivity<DB : ViewDataBinding, VM : BaseViewModel> : DaggerAppCompatActivity() {
private lateinit var mCustomDialog: CustomDialog
private lateinit var mViewDataBinding: DB
private lateinit var mViewModel : VM
#Inject
lateinit var viewModelFactory: ViewModelFactory
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Set Custom Dialog
mCustomDialog = CustomDialog(this, R.style.LoadingDialogStyle)
// Set ViewModel
mViewModel = ViewModelProviders.of(this, viewModelFactory).get(getViewModelClass().java)
// Set DataBinding
mViewDataBinding = DataBindingUtil.setContentView(this, getLayoutId())
mViewDataBinding.lifecycleOwner = this
mViewDataBinding.setVariable(getBindingVariable(), mViewModel)
mViewDataBinding.executePendingBindings()
// Initialize UI
prepareView(savedInstanceState)
}
#LayoutRes
abstract fun getLayoutId(): Int
protected abstract fun getViewModelClass(): KClass<VM>
abstract fun getBindingVariable(): Int
fun getViewModel(): VM {
return mViewModel
}
fun getViewDataBinding() : DB {
return mViewDataBinding
}
I am using protected abstract fun getViewModelClass(): KClass<VM> function for initializing ViewModel class in the function below
ViewModelProviders.of(this, viewModelFactory).get(getViewModelClass().java)
I use ViewModel in activities by this way
class SplashActivity : BaseActivity<ActivitySplashBinding, SplashViewModel>() {
override fun getViewModelClass(): KClass<SplashViewModel> {
return SplashViewModel::class
}
override fun getLayoutId(): Int {
return R.layout.activity_splash
}
override fun getBindingVariable(): Int {
return BR.vm
}
override fun prepareView(savedInstanceState: Bundle?) {
getViewModel().testLog()
}
}
But when I run the project, I got this error
error: [Dagger/MissingBinding] java.util.Map<java.lang.Class<? extends androidx.lifecycle.ViewModel>,javax.inject.Provider<androidx.lifecycle.ViewModel>> cannot be provided without an #Provides-annotated method.
public abstract interface AppComponent extends dagger.android.AndroidInjector<com.example.example.MyApp> {
^
java.util.Map<java.lang.Class<? extends androidx.lifecycle.ViewModel>,javax.inject.Provider<androidx.lifecycle.ViewModel>> is injected at
com.example.example.utils.ViewModelFactory(viewModels)
com.example.example.utils.ViewModelFactory is injected at
com.example.example.base.BaseActivity.viewModelFactory
com.example.example.ui.splash.SplashActivity is injected at
dagger.android.AndroidInjector.inject(T) [com.example.example.di.AppComponent ? com.example.example.di.ActivityBindingsModule_SplashActivityInjector$app_debug.SplashActivitySubcomponent]
So I made some research and find out it is about KClass in my ViewModelKey
Here is ViewModelKey
#Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
#Retention(AnnotationRetention.RUNTIME)
#MapKey
annotation class ViewModelKey(val value: KClass<out ViewModel>)
If I do not change my code to Kotlin and use old Java class like this it works properly
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
#MapKey
public #interface ViewModelKey {
Class<? extends ViewModel> value();
}
This is my ViewModelFactory class
#Suppress("UNCHECKED_CAST")
class ViewModelFactory #Inject
constructor(private val viewModels: MutableMap<Class<out ViewModel>, #JvmSuppressWildcards Provider<ViewModel>>) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
val creator = viewModels[modelClass]
?: viewModels.asIterable().firstOrNull { modelClass.isAssignableFrom(it.key) }?.value
?: throw IllegalArgumentException("unknown model class $modelClass")
return try {
creator.get() as T
} catch (e: Exception) {
throw RuntimeException(e)
}
}
}
My SplashActivityModule
#Module
abstract class SplashActivityModule {
#Binds
#IntoMap
#ViewModelKey(SplashViewModel::class)
internal abstract fun provideSplashViewModel(splashViewModel: SplashViewModel) : ViewModel
}
So how can I use ViewModelKey properly with Kotlin and what is main cause of this error, any help will be appreciated
Your ViewModelKey be like
#MustBeDocumented
#kotlin.annotation.Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
#kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
#MapKey
internal annotation class ViewModelKey(val value: KClass<out ViewModel>)
As mentioned this question problem is related to Kotlin version. Using higher than 1.3.30 version solves the problem.