Not able to change language locale in Kotlin - android

I have 2 string files "en" and "es". When ever I am changing the locale in locale manager class, it saves the new locale successfully but does not reflect changes on refreshing activity.
MyApplication.kt
open class MyApplication : Application() {
init {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}
override fun attachBaseContext(base: Context?) {
super.attachBaseContext(LocaleManagerMew.setLocale(base))
// MultiDex.install(base)
}
override fun onCreate() {
super.onCreate()
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
LocaleManagerMew.setLocale(this)
Log.d("app", "onConfigurationChanged: " + newConfig.locale.getLanguage())
}
}
LocaleManagerNew.kt
object LocaleManagerMew {
val SELECTED_LANGUAGE = "MEW_CURRENT_-- USER_LANGUAGE"
var mSharedPreference: SharedPref? = null
var mEnglishFlag = "en"
var mSpanishFlag = "es"
fun setLocale(context: Context?): Context {
return updateResources(context!!, getCurrentLanguage(context)!!)
}
inline fun setNewLocale(context: Context, language: String) {
persistLanguagePreference(context, language)
updateResources(context, language)
}
inline fun getCurrentLanguage(context: Context?): String? {
var mCurrentLanguage: String?
if (mSharedPreference == null)
mSharedPreference = SharedPref(context!!)
mCurrentLanguage = mSharedPreference!!.getSavedLang()
return mCurrentLanguage
}
fun persistLanguagePreference(context: Context, language: String) {
if (mSharedPreference == null)
mSharedPreference = SharedPref(context!!)
mSharedPreference!!.setSavedLang(language)
}
fun updateResources(context: Context, language: String): Context {
var contextFun = context
var locale = Locale(language)
Locale.setDefault(locale)
var resources = context.resources
var configuration = Configuration(resources.configuration)
if (Build.VERSION.SDK_INT >= 17) {
configuration.setLocale(locale)
contextFun = context.createConfigurationContext(configuration)
} else {
configuration.locale = locale
resources.updateConfiguration(configuration, resources.getDisplayMetrics())
}
return contextFun
}
}
BaseActivity.kt
override fun attachBaseContext(base: Context?) {
super.attachBaseContext(LocaleManagerMew.setLocale(base))
}
MainActivity.kt
R.id.spanishCL -> {
sp.setSavedLang("es")
var mCurrentLanguage = LocaleManagerMew.getCurrentLanguage(this#MainActivity.applicationContext)
LocaleManagerMew.setNewLocale(this#MainActivity, LocaleManagerMew.mSpanishFlag)
mContext?.recreate()
}
This is the onClick method call to change english locale to spanish. After recreating acitivity new locale changes does not reflect

Try the below code for updating language from attachBaseContext of every Activity
fun setLanguage(context: Context, language: String): ContextWrapper {
var mContext = context
val localeLang = language.split("_".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val locale: Locale
if (localeLang.size > 1)
locale = Locale(localeLang[0], localeLang[1])
else
locale = Locale(localeLang[0])
val res = mContext.resources
val configuration = res.configuration
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val localeList = LocaleList(locale)
LocaleList.setDefault(localeList)
configuration.locales = localeList
mContext = mContext.createConfigurationContext(configuration)
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
configuration.setLocale(locale)
mContext = mContext.createConfigurationContext(configuration)
} else {
configuration.locale = locale
res.updateConfiguration(configuration, res.getDisplayMetrics())
}
return ContextWrapper(mContext)
}
And implementation in attachBaseContext of Activity class
// For Language Changing
override fun attachBaseContext(newBase: Context?) {
super.attachBaseContext(newBase?.let {
Common.setLanguage(
it,
PreferenceManager.getPref<String>(Constants.LANGUAGE_PREFERENCE).toString()
)
})
}
And this is how I restart the activity from fragment
Handler().post {
val intent = activity?.intent
intent?.flags =
Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK or
Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NO_ANIMATION
activity?.overridePendingTransition(0, 0)
activity?.finish()
activity?.overridePendingTransition(0, 0)
startActivity(intent)
}

Related

how to get Callback when call ends or decline using CallScreenService in android?

I am using CallScreenService Api to detect call and show window on incoming and outgoing calls, but I want to close my overlay dialog window when calls ends or decline.
Here is my code for CallScreenService.class
class AppService : CallScreeningService() {
#Inject
lateinit var applicationRepository: ApplicationRepository
#Inject
lateinit var telephonyManager: TelephonyManager
private val windowManagerForNumber by lazy {
WindowManagerForNumber(this)
}
private var finalPhoneNumb: String? = ""
private val callerName: String?
get() = finalPhoneNumb?.let {
applicationRepository.fetchNameFromPhoneNumber(
it
)
}
private val notificationManagerImpl = NotificationManagerImpl()
private val notification by lazy {
com.example.truecaller.calling_app.utils.notification.Notification(this)
}
companion object {
fun startService(context: Context) {
Intent(context, TrueCallerAppService::class.java).apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(context, this)
} else {
context.startService(this)
}
}
}
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
super.onStartCommand(intent, flags, startId)
startNotification()
return START_STICKY
}
override fun onScreenCall(p0: Call.Details) {
val number = getPhoneNumber(p0)
var callResponse = CallResponse.Builder()
callResponse = handlePhoneCall(callResponse, number)
respondToCall(p0, callResponse.build())
}
private fun handlePhoneCall(
response: CallResponse.Builder,
phoneNumber: String
): CallResponse.Builder {
if (phoneNumber == FORBIDDEN_PHONE_CALL_NUMBER) {
response.apply {
setRejectCall(true)
setDisallowCall(true)
setSkipCallLog(false)
}
} else {
if (Settings.canDrawOverlays(this)) {
finalPhoneNumb = phoneNumber
if (PhoneNumberValidCheck.checkValidPhoneNumber(phoneNumber)) {
displayToast(phoneNumber)
Log.e("phone", "handlePhoneCall: $phoneNumber")
}
}
}
return response
}
private fun startNotification() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForeground(notification.notificationId, notification.createNotification())
} else {
startForeground(
notification.notificationId,
android.app.Notification()
)
}
isForeGroundService = true
}
private fun displayToast(message: String) {
try {
val countryCodeOfNumber = telephonyManager.simCountryIso.toString()
val phoneNumberUtil = PhoneNumberUtil.getInstance()
val phoneNumber: Phonenumber.PhoneNumber =
phoneNumberUtil.parse(message, countryCodeOfNumber.uppercase(Locale.ENGLISH))
val incomingNumber = phoneNumberUtil.format(phoneNumber, PhoneNumberUtil.PhoneNumberFormat.E164)
notificationManagerImpl.appRepo(applicationRepository, windowManagerForNumber, incomingNumber)
} catch (e: Exception) {
e.printStackTrace()
}
}
Here is my WindowManagerClass
class WindowManagerForNumber(private val context: Context) {
private var mView: View? = null
private var mParams: WindowManager.LayoutParams? = null
private var mWindowManager: WindowManager? = null
private var layoutInflater: LayoutInflater? = null
private var bool: Boolean = false
private var callerNumber: String? = null
private var callerName: String? = null
private var dialogCallerSearchBinding: DialogCallerSearchBinding? = null
private val scope = CoroutineScope(Job())
init {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mParams = WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
FLAG_NOT_FOCUSABLE or FLAG_SHOW_WHEN_LOCKED,
PixelFormat.TRANSLUCENT
)
}
layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
layoutInflater?.let {
dialogCallerSearchBinding =
DialogCallerSearchBinding.inflate(it, null, false)
mView = dialogCallerSearchBinding?.root
mView?.isFocusableInTouchMode = true
mView?.requestFocus()
mView?.setOnKeyListener { v,keyCode,event ->
if(keyCode == KeyEvent.KEYCODE_BACK){
close()
return#setOnKeyListener true
}
return#setOnKeyListener false
}
dialogCallerSearchBinding?.apply {
tvCallingName.text = callerName
tvCallingNumber.text = callerNumber
ivClose.onClickListener {
close()
}
}
mParams?.gravity = Gravity.CENTER
mWindowManager = context.getSystemService(WINDOW_SERVICE) as WindowManager
}
}
fun setData(
name: String,
number: String?,
appRepository: ApplicationRepository,
isDataSet: (Boolean) -> Unit
) {
scope.launch(Dispatchers.Main) {
dialogCallerSearchBinding?.apply {
number?.let {
when (val data = appRepository.fetchContactData(it)) {
is ResultOfResponse.ResponseEmpty -> {
progressBar.isVisible = false
contactDetail.isVisible = true
tvCallingName.text =
context.resources.getString(R.string.no_name_found)
tvCountryName.isVisible = false
tvCallingNumber.text = number
isDataSet(true)
}
is ResultOfResponse.ResponseError -> {
progressBar.isVisible = false
contactDetail.isVisible = true
tvCallingName.text =
context.resources.getString(R.string.no_name_found)
tvCountryName.isVisible = false
tvCallingNumber.text = number
isDataSet(true)
}
ResultOfResponse.ResponseLoading -> {
}
is ResultOfResponse.ResponseSuccess -> {
progressBar.isVisible = false
contactDetail.isVisible = true
tvCountryName.isVisible = true
tvCallingName.text = data.data.ContactName
tvCallingNumber.text = data.data.ContactUuid
tvCountryName.text = data.data.ContactCountry
dialogCallerSearchBinding?.ivContactImage?.let { it1 ->
appRepository.fetchContactImage(
it,
it1, name
)
}
isDataSet(true)
}
}
}
/*if (name.contentEquals(PRIVATE_NUMBER)) {
progressBar.isVisible = false
contactDetail.isVisible = true
tvCallingName.text = PRIVATE_NUMBER
tvCountryName.visibility = View.INVISIBLE
tvCallingNumber.text = number
isDataSet(true)
} else {
}*/
}
}
}
fun open() {
try {
if (mView?.windowToken == null) {
if (mView?.parent == null) {
mWindowManager?.addView(mView, mParams)
bool = true
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
fun close() {
if (bool) {
mWindowManager?.removeView(mView)
mView?.invalidate()
bool = false
dialogCallerSearchBinding?.apply {
tvCallingName.text = null
tvCountryName.text = null
tvCallingNumber.text = null
}
}
}
}
I am using WindowManager for showing overlay dialog window and closing window when user click "x" (cross imageView) but I want to close window when call ends or decline.

Android- Could not get shared preferences when attaching base context

i am working on adding international support to our app, each country has multiple languages and one of them is default, when the app is launched in the first launch the user choose a country then i save it in sharedPreferences with the default language, then he can change the language in the next screen,
in a BaseActivity i'm overriding attachBaseContext() function then i call a function in our LocalHelper that returns a context with the desired configuration,
the problem is i'm not able to fetch the country and the language from sharedPreferences in this level, it returns all time empty preferences, and in other places i get them without problem.
here us the function that returns the context with desired configuration:
fun setupLanguage(context: Context): Context {
val res = context.resources
val config = res.configuration
val json = Json { ignoreUnknownKeys = true }
val currentCountryPreferences = context.getSharedPreferences(
CURRENT_COUNTRY_PREFERENCES, Context.MODE_PRIVATE
)
val currentCountryLanguagePreferences = context.getSharedPreferences(
CURRENT_COUNTRY_LANGUAGE_PREFERENCES, Context.MODE_PRIVATE
)
val currentCountryString = currentCountryPreferences.getString(
CURRENT_COUNTRY_KEY, ""
)
val currentCountryLanguageString = currentCountryLanguagePreferences.getString(
CURRENT_COUNTRY_LANGUAGE_KEY, ""
)
val currentLanguage = try {
currentCountryLanguageString?.let {
json.decodeFromString(
Language.serializer(),
it
)
}
} catch (e: Exception) {
Timber.e(e)
null
}
val currentCountry = try {
currentCountryString?.let {
json.decodeFromString(
Country.serializer(),
it
)
}
} catch (e: Exception) {
Timber.e(e)
null
}
if (currentLanguage != null && currentCountry != null) {
if (!currentLanguage.code.isNullOrEmpty() && !currentCountry.code.isNullOrEmpty()) {
val language = currentLanguage.code
val countryCode = currentCountry.code?.uppercase()
val locale = Locale(language, countryCode)
Locale.setDefault(locale)
config.setLocale(locale)
when (language) {
AppLocal.ENGLISH.language -> {
config.setLayoutDirection(AppLocal.ENGLISH)
}
AppLocal.FRENCH.language -> {
config.setLayoutDirection(AppLocal.FRENCH)
}
AppLocal.ARABIC.language -> {
config.setLayoutDirection(AppLocal.ARABIC)
}
AppLocal.ARABIC_MOROCCO.language -> {
config.setLayoutDirection(AppLocal.ARABIC_MOROCCO)
}
}
}
}
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
context.createConfigurationContext(config)
} else {
val resources = context.resources
resources.updateConfiguration(config, resources.displayMetrics)
context
}
}

Launch new Activity from FrameLayout

I try to study overlay library for kotlin applications https://github.com/KoderLabs/overlay-service. Right now I have a problem related with opening a new activity from a button which is located inside a FrameLayout class.
So, the task is push on button on Main Activity -> open new overlay small window and roll up Main Activity -> push on button inside a small window -> open new Activity.
In this code nothing happens after the clicking on button.
The project include main 3 classes:
MainActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
btn_simple_pip.setOnClickListener {
checkDrawOverlayPermission(IMPLEMENTED_PIP_OVERLAY_REQUEST_CODE)
finishAffinity()
}
}
private fun checkDrawOverlayPermission(code: Int) {
if (Build.VERSION.SDK_INT >= 23) {
if (!Settings.canDrawOverlays(this)) {
val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:$packageName"))
startActivityForResult(intent, IMPLEMENTED_PIP_OVERLAY_REQUEST_CODE)
} else {
openFloatingWindow(code)
}
} else {
openFloatingWindow(code)
}
}
private fun openFloatingWindow(code: Int) {
when (code) {
IMPLEMENTED_PIP_OVERLAY_REQUEST_CODE -> {
val intent = Intent(this, ImplementPipOverlayService::class.java)
val videoUrl =
"https://s3.amazonaws.com/data.development.momentpin.com/2019/7/3/1562152168485485-0661a550-9d83-11e9-9028-d7af09cf782e.mp4"
val notificationTitle = "Pip Overlay"
val notificationDescription = "Pip overlay description"
val notificationIcon = R.drawable.ic_launcher_foreground
val closeBtnColor = android.R.color.black
val closeBtnBgColor = android.R.color.transparent
intent.putExtra(ImplementPipOverlayService.KEY_STRING_VIDEO_URL, videoUrl)
intent.putExtra(ImplementPipOverlayService.KEY_STRING_NOTIFICATION_DESCRIPTION, notificationDescription)
intent.putExtra(ImplementPipOverlayService.KEY_STRING_NOTIFICATION_TITLE, notificationTitle)
intent.putExtra(ImplementPipOverlayService.KEY_INT_NOTIFICATION_ICON, notificationIcon)
intent.putExtra(ImplementPipOverlayService.KEY_INT_CLOSE_BUTTON_COLOR, closeBtnColor)
intent.putExtra(ImplementPipOverlayService.KEY_INT_CLOSE_BUTTON_BG_COLOR, closeBtnBgColor)
ContextCompat.startForegroundService(this, intent)
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) {
IMPLEMENTED_PIP_OVERLAY_REQUEST_CODE, RESIZEABLE_CUSTOM_WEB_OVERLAY_REQUEST_CODE,
PIP_OVERLAY_REQUEST_CODE, RESIZEABLE_CUSTOM_VIDEO_OVERLAY_REQUEST_CODE -> {
if (Build.VERSION.SDK_INT >= 23) {
if (Settings.canDrawOverlays(this)) {
openFloatingWindow(requestCode)
}
} else {
openFloatingWindow(requestCode)
}
}
}
super.onActivityResult(requestCode, resultCode, data)
}
companion object {
const val IMPLEMENTED_PIP_OVERLAY_REQUEST_CODE = 251
const val PIP_OVERLAY_REQUEST_CODE = 252
const val RESIZEABLE_CUSTOM_VIDEO_OVERLAY_REQUEST_CODE = 253
const val RESIZEABLE_CUSTOM_WEB_OVERLAY_REQUEST_CODE = 254
}
ImplementPipOverlayService
class ImplementPipOverlayService : PipOverlayService() {
var videoUrl: String? = null
var notificationTitle: String? = null
var notificationDescription: String? = null
var notificationIcon: Int? = null
var closeButtonColor: Int? = null
var closeButtonBg: Int? = null
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
videoUrl = intent?.getStringExtra(KEY_STRING_VIDEO_URL)
notificationTitle = intent?.getStringExtra(KEY_STRING_NOTIFICATION_TITLE)
notificationDescription = intent?.getStringExtra(KEY_STRING_NOTIFICATION_DESCRIPTION)
notificationIcon = intent?.getIntExtra(KEY_INT_NOTIFICATION_ICON, -1)
closeButtonColor = intent?.getIntExtra(KEY_INT_CLOSE_BUTTON_COLOR, -1)
closeButtonBg = intent?.getIntExtra(KEY_INT_CLOSE_BUTTON_BG_COLOR, -1)
return super.onStartCommand(intent, flags, startId)
}
override fun getForegroundNotification(): Notification {
val channelId =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createNotificationChannel("my_service", "My Background Service")
} else {
packageName
}
var notificationBuilder = NotificationCompat.Builder(this, channelId)
notificationBuilder = notificationTitle?.let {
notificationBuilder.setContentTitle(it)
} ?: run {
notificationBuilder.setContentTitle("Title")
}
notificationDescription?.let {
notificationBuilder = notificationBuilder.setContentText(it)
}
notificationIcon?.let {
notificationBuilder = notificationBuilder.setSmallIcon(it)
}
val notification: Notification = notificationBuilder.build()
return notification
}
#RequiresApi(Build.VERSION_CODES.O)
private fun createNotificationChannel(channelId: String, channelName: String): String {
val chan = NotificationChannel(channelId,
channelName, NotificationManager.IMPORTANCE_NONE)
chan.lightColor = Color.BLUE
chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
val service = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
service.createNotificationChannel(chan)
return channelId
}
override fun getInitialWindowSize(): Point {
return Point(100.toDp(), 100.toDp())
}
override fun getCustomLayoutId(): Int {
return R.layout.pip_layout
}
override fun onServiceRun() {
setOnEventListener(onFullscreen = {
// Not implemented
}, onClosed = {
// Not implemented
})
pipView.removeFullscreenButton()
closeButtonColor?.let {
pipView.getCloseButton().setColorFilter(it)
}
closeButtonBg?.let {
pipView.getCloseButton().setBackgroundColor(it)
}
}
companion object {
const val KEY_STRING_VIDEO_URL = "video_url"
const val KEY_INT_CLOSE_BUTTON_COLOR = "close_button_color"
const val KEY_INT_CLOSE_BUTTON_BG_COLOR = "close_button_background"
const val KEY_STRING_NOTIFICATION_TITLE = "notification_title"
const val KEY_STRING_NOTIFICATION_DESCRIPTION = "notification_description"
const val KEY_INT_NOTIFICATION_ICON = "notification_icon"
}
OverlayPipCustomView
class OverlayPipCustomView : FrameLayout {
private lateinit var constraintsRoot: ConstraintLayout
private lateinit var imageFullscreenButton: ImageView
private lateinit var imageCloseButton: ImageView
private lateinit var customLayoutContent: FrameLayout
private lateinit var customView: View
private lateinit var touchView: View
private lateinit var button: Button
private var playerViewSize: Int = 0
private var sizeChangeable: Boolean = true
private var playerType: Int = 0
private var haveFullscreen = true
/**
* Tracks if viewResizeable is fullscreen.
*/
private var fullscreenOn: Boolean = false
val isDraggable: Boolean
get() {
return !fullscreenOn
}
private var onFullscreen: () -> Unit = {}
private var onClosed: () -> Unit = {}
private var canHideActionButtons = true
private val hideActionHandler = Handler()
private val HIDE_ACTION_DURATION = 2000L
private val hideActionRunnable = Runnable {
if (!isMoving) {
hideActions()
}
}
var isMoving: Boolean = false
constructor(ctx: Context) : super(ctx) {
inflate(context, R.layout.layout_pip_custom_view, this)
initView()
}
constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs) {
setAttributes(attrs)
inflate(context, R.layout.layout_pip_custom_view, this)
initView()
}
constructor(ctx: Context, attrs: AttributeSet, defStyle: Int) : super(ctx, attrs, defStyle) {
setAttributes(attrs)
inflate(context, R.layout.layout_pip_custom_view, this)
initView()
}
private fun setAttributes(attrs: AttributeSet) {
context.theme.obtainStyledAttributes(
attrs,
R.styleable.OverlayCustomView,
0, 0).apply {
try {
playerViewSize = getInteger(R.styleable.OverlayCustomView_ov_player_size, 0)
playerType = getInteger(R.styleable.OverlayCustomView_ov_size_changeable, 0)
sizeChangeable = getBoolean(R.styleable.OverlayCustomView_ov_size_changeable, true)
} finally {
recycle()
}
}
doOnLayout {
startHideAction()
}
}
private fun initView() {
button = findViewById(R.id.button)
constraintsRoot = findViewById(R.id.constraints_root)
imageFullscreenButton = findViewById(R.id.image_screen_action)
imageCloseButton = findViewById(R.id.image_close)
customLayoutContent = findViewById(R.id.custom_view)
touchView = findViewById(R.id.touch_view)
setListeners()
}
fun addCustomView(view: View) {
customLayoutContent.addView(view)
}
fun addCustomView(layoutId: Int) {
customView = inflate(context, layoutId, null)
customLayoutContent.addView(customView)
}
fun getCloseButton() = imageCloseButton
fun getConstraintsRoot() = constraintsRoot
fun getCustomLayoutContent() = customLayoutContent
fun getCustomView() = customView
fun getFullscreenButton() = imageFullscreenButton
fun getTouchView() = touchView
fun removeFullscreenButton() {
haveFullscreen = false
imageFullscreenButton.invisible()
}
private fun setListeners() {
imageFullscreenButton.setOnClickListener {
onFullscreen.invoke()
}
button.setOnClickListener{
println("pressed")
fun alert(context: Context, text: String) {
val intent = Intent(context, MainActivity2::class.java)
intent.putExtra("text", text)
context.startActivity(intent)
}
}
imageCloseButton.setOnClickListener {
onClosed.invoke()
}
}
fun setOnEventActionListener(
onFullscreen: () -> Unit,
onClosed: () -> Unit
) {
this.onFullscreen = onFullscreen
this.onClosed = onClosed
}
private fun startHideAction() {
if (canHideActionButtons) {
hideActionHandler.postDelayed(hideActionRunnable, HIDE_ACTION_DURATION)
}
}
fun restartHideAction() {
hideActionHandler.removeCallbacks(hideActionRunnable)
if (canHideActionButtons) {
hideActionHandler.postDelayed(hideActionRunnable, HIDE_ACTION_DURATION)
}
}
fun hideActions() {
if (canHideActionButtons) {
imageCloseButton.invisible()
if (haveFullscreen) {
imageFullscreenButton.invisible()
}
}
}
fun showActions() {
imageCloseButton.visible()
if (haveFullscreen) {
imageFullscreenButton.visible()
}
}
}
In third class I can't understand what should be placed here to to change initial first Activity to another one
button.setOnClickListener{
println("pressed")
fun alert(context: Context, text: String) {
val intent = Intent(context, MainActivity2::class.java)
intent.putExtra("text", text)
context.startActivity(intent)
}
}
startService(intent) will try and start a new Service and unfortunately does not throw an error if you call it with an Activity class.
To launch MainActivity2 instead call context.startActivity(intent).

Locale always get reset after onCreate

I try to setting locale in app, first run it works. But, after onCreate() (Rotate) will get reset to default language and I can't change language in app after reset.
I use SharePreference to save locale value
PrefUtils.java to get value from SharePreference
public class PrefUtil {
private static final String PREF_SETTINGS_LANGUAGE = "pref_settings_language";
public static String getLocale(Context context){
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
String loadLanguage = sharedPreferences.getString(PREF_SETTINGS_LANGUAGE, "");
Log.d("LoadLanguage", loadLanguage);
return loadLanguage;
}
}
MainActivity.java to set locale, I put in onCreate and onResume
private void appLocale(String localeCode){
Locale locale = new Locale(localeCode);
Locale.setDefault(locale);
Configuration configuration = getBaseContext().getResources().getConfiguration();
configuration.locale = locale;
getBaseContext().getResources().updateConfiguration(configuration, getBaseContext().getResources().getDisplayMetrics());
}
In activity class, you should override attachBaseContext(base : Context).
Create an abstract class BaseActivity and extends it on MainActivity.
By doing this you don't have to write onAttachBaseContext() in every activity class but should extend BaseActivity instead of AppCompatActivity.
class BaseActivity : AppCompatActivity {
override fun attachBaseContext(base: Context) {
super.attachBaseContext(LocaleHelper.onAttach(base))
}
}
To retain language setting you should also override attachBaseContext(base:Context) in Application class.
class App : Application() {
override fun attachBaseContext(base: Context) {
super.attachBaseContext(LocaleHelper.onAttach(base, LocaleHelper.LANG_EN))
}
}
If you need a helper class of localization, here is the one. The code is in Kotlin, but I think you will understand.
object LocaleHelper {
private const val SELECTED_LANGUAGE = "Locale.Helper.Selected.Language"
const val LANG_EN = "en"
const val LANG_ES = "es"
val languageMap = hashMapOf(
LANG_EN to "English",
LANG_ES to "Spanish"
)
fun onAttach(context: Context): Context {
val lang = getPersistedData(context, Locale.getDefault().language)
return setLocale(context, lang)
}
fun onAttach(context: Context, defaultLanguage: String): Context {
val lang = getPersistedData(context, defaultLanguage)
return setLocale(context, lang)
}
fun getLanguage(context: Context): String? {
return getPersistedData(context, Locale.getDefault().language)
}
fun setLocale(context: Context, language: String?): Context {
persist(context, language)
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
updateResources(context, language)
} else {
updateResourcesLegacy(context, language)
}
}
private fun getPersistedData(context: Context, defaultLanguage: String): String? {
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
return preferences.getString(SELECTED_LANGUAGE, defaultLanguage)
}
private fun persist(context: Context, language: String?) {
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
val editor = preferences.edit()
editor.putString(SELECTED_LANGUAGE, language)
editor.apply()
}
#TargetApi(Build.VERSION_CODES.N)
private fun updateResources(context: Context, language: String?): Context {
val locale = Locale(language)
Locale.setDefault(locale)
val configuration = context.resources.configuration
configuration.setLocale(locale)
configuration.setLayoutDirection(locale)
return context.createConfigurationContext(configuration)
}
// used for api level < 24
#Suppress("DEPRECATION")
private fun updateResourcesLegacy(context: Context, language: String?): Context {
val locale = Locale(language)
Locale.setDefault(locale)
val resources = context.resources
val configuration = resources.configuration
configuration.locale = locale
resources.updateConfiguration(configuration, resources.displayMetrics)
return context
}
}

Resources not getting updated after changing locale

My app supports two languages(English and Spanish). When I change the locale from English(en) to Spanish(es) it succeeds (Locale get changed). But, resources are not getting updated. I am recreating the activity after updated the Locale.
I have debugged the app on Splash screen after changing the Locale. and check the current Locale (returned 'es'). but still, the strings are not getting updated. The Spanish string file is put under the values-es package.
Also tried running the same localization code by creating a new application and it worked.
Following is the code:
VerifiApp.kt:
class VerifiApp : Application(), HasActivityInjector {
#Inject
lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Activity>
override fun onCreate() {
super.onCreate()
if (BuildConfig.DEBUG) {
Timber.plant(Timber.DebugTree())
}
AppInjector.init(this)
}
override fun attachBaseContext(base: Context?) {
super.attachBaseContext(LocaleHelper.onAttach(base!!, "en"))
}
override fun activityInjector() = dispatchingAndroidInjector
}
SelectLanguageActivity.kt:
class SelectLanguageActivity : BaseActivity<SelectLanguageViewModel>() {
private var languageCode = ""
#Inject
lateinit var appDataManager: AppDataManager
#Inject
lateinit var appViewModelFactory: AppViewModelFactory
private lateinit var selectLanguageViewModel: SelectLanguageViewModel
private lateinit var languageAdapter: ArrayAdapter<Language>
private var languageList = ArrayList<Language>()
override fun getViewModel(): SelectLanguageViewModel {
selectLanguageViewModel = ViewModelProviders.of(this#SelectLanguageActivity, appViewModelFactory)
.get(SelectLanguageViewModel::class.java)
return selectLanguageViewModel
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_select_language)
languageList.add(Language("English", "en"))
languageList.add(Language("Spanish", "es"))
languageAdapter = ArrayAdapter(this, R.layout.item_spinner_dropdown, languageList)
spinnerLanguage.adapter = languageAdapter
spinnerLanguage.apply {
onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onNothingSelected(parent: AdapterView<*>?) {
}
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
languageCode = languageList[position].languageCode
}
}
}
btnUpdate.setOnClickListener {
val context = LocaleHelper.setLocale(this, languageCode)
val resources = context.resources
val bundle = Bundle()
bundle.putString("language_code", languageCode)
val intent = Intent(applicationContext, AuthActivity::class.java)
intent.putExtras(bundle)
startActivity(intent)
}
}
}
BaseActivity.kt:
abstract class BaseActivity<out V : ViewModel> : AppCompatActivity(), BaseFragment.Callback {
private lateinit var mViewModel: V
private lateinit var progressDialog: Dialog
override fun onCreate(savedInstanceState: Bundle?) {
performDependencyInjection()
super.onCreate(savedInstanceState)
initializeProgressLoader()
}
private fun initializeProgressLoader() {
progressDialog = Dialog(this)
progressDialog.setCancelable(false)
progressDialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
progressDialog.window.setBackgroundDrawableResource(android.R.color.transparent)
progressDialog.setContentView(R.layout.dialog_progress)
}
fun setProgressVisibility(visible: Boolean) {
if (visible) {
progressDialog.show()
} else {
progressDialog.dismiss()
}
}
private fun performDependencyInjection() {
AndroidInjection.inject(this)
mViewModel = getViewModel()
}
override fun onFragmentAttached() {
}
override fun onFragmentDetached(tag: String) {
}
fun isNetworkConnected(): Boolean {
val flag = NetworkUtils.isNetworkConnected(applicationContext)
if (!flag) {
showErrorToast("Internet not connected!")
}
return flag
}
fun hideKeyboard() {
val view: View? = this.currentFocus
val inputMethodManager: InputMethodManager =
getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
inputMethodManager.hideSoftInputFromWindow(view?.windowToken, 0)
}
fun showErrorToast(message: String) {
ColorToast.makeText(this, message, ColorToast.LENGTH_SHORT, ColorToast.ERROR, false).show()
}
fun showInfoToast(message: String) {
ColorToast.makeText(this, message, ColorToast.LENGTH_SHORT, ColorToast.INFO, false).show()
}
fun showSuccessToast(message: String) {
ColorToast.makeText(this, message, ColorToast.LENGTH_SHORT, ColorToast.SUCCESS, false).show()
}
/**
* Override for set view model
*
* #return ViewModel instance
* */
abstract fun getViewModel(): V
override fun attachBaseContext(newBase: Context?) {
super.attachBaseContext(LocaleHelper.onAttach(newBase!!))
}
}
LocaleHelper.java
public class LocaleHelper {
private static final String SELECTED_LANGUAGE = "Locale.Helper.Selected.Language";
public static Context onAttach(Context context) {
String lang = getPersistedData(context, Locale.getDefault().getLanguage());
return setLocale(context, lang);
}
public static Context onAttach(Context context, String defaultLanguage) {
String lang = getPersistedData(context, defaultLanguage);
return setLocale(context, lang);
}
public static String getLanguage(Context context) {
return getPersistedData(context, Locale.getDefault().getLanguage());
}
public static Context setLocale(Context context, String language) {
persist(context, language);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
return updateResources(context, language);
}
return updateResourcesLegacy(context, language);
}
private static String getPersistedData(Context context, String defaultLanguage) {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
return preferences.getString(SELECTED_LANGUAGE, defaultLanguage);
}
private static void persist(Context context, String language) {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor editor = preferences.edit();
editor.putString(SELECTED_LANGUAGE, language);
editor.apply();
}
#TargetApi(Build.VERSION_CODES.N)
private static Context updateResources(Context context, String language) {
Locale locale = new Locale(language);
Locale.setDefault(locale);
Configuration configuration = context.getResources().getConfiguration();
configuration.setLocale(locale);
configuration.setLayoutDirection(locale);
return context.createConfigurationContext(configuration);
}
#SuppressWarnings("deprecation")
private static Context updateResourcesLegacy(Context context, String language) {
Locale locale = new Locale(language);
Locale.setDefault(locale);
Resources resources = context.getResources();
Configuration configuration = resources.getConfiguration();
configuration.locale = locale;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
configuration.setLayoutDirection(locale);
}
resources.updateConfiguration(configuration, resources.getDisplayMetrics());
return context;
}
}
Help would be really appreciated. Thanks.

Categories

Resources