Telegram - cleanup code

This commit is contained in:
crimean 2018-06-11 19:57:33 +03:00
parent 824d608c86
commit 911126e3f9
20 changed files with 2611 additions and 2711 deletions

View file

@ -33,25 +33,14 @@
</activity>
<service
android:name=".services.MyLocationService"
android:label="@string/process_location_service"
android:name=".TelegramService"
android:label="@string/process_service"
android:stopWithTask="false">
<intent-filter>
<action android:name="net.osmand.telegram.services.MyLocationService" />
<action android:name="net.osmand.telegram.TelegramService" />
</intent-filter>
</service>
<service
android:name=".services.UserLocationService"
android:label="@string/process_location_service"
android:stopWithTask="false">
<intent-filter>
<action android:name="net.osmand.telegram.services.UserLocationService" />
</intent-filter>
</service>
<receiver android:name=".notifications.NotificationDismissReceiver" />
</application>
</manifest>

View file

@ -27,7 +27,7 @@
<string name="shared_string_pause">Pause</string>
<string name="shared_string_start">Start</string>
<string name="shared_string_stop">Stop</string>
<string name="process_location_service">OsmAnd Telegram location service</string>
<string name="process_service">OsmAnd Telegram service</string>
<string name="osmand_logo">OsmAnd logo</string>
<string name="install_osmand_dialog_message">You need to install free or paid version of OsmAnd first</string>
<string name="install_osmand">Install OsmAnd</string>

View file

@ -4,143 +4,143 @@ import org.apache.commons.logging.Log;
public class PlatformUtil {
public static String TAG = "net.osmand";
private static class OsmandLogImplementation implements Log {
public static String TAG = "net.osmand";
private final String fullName;
private final String name;
private static class OsmandLogImplementation implements Log {
public OsmandLogImplementation(String name){
this.fullName = name;
this.name = fullName.substring(fullName.lastIndexOf('.') + 1);
}
private final String fullName;
private final String name;
@Override
public void trace(Object message) {
if(isTraceEnabled()){
android.util.Log.d(TAG, name + " " + message);
}
}
public OsmandLogImplementation(String name) {
this.fullName = name;
this.name = fullName.substring(fullName.lastIndexOf('.') + 1);
}
@Override
public void trace(Object message, Throwable t) {
if(isTraceEnabled()){
android.util.Log.d(TAG, name + " " + message, t);
}
}
@Override
public void trace(Object message) {
if (isTraceEnabled()) {
android.util.Log.d(TAG, name + " " + message);
}
}
@Override
public void debug(Object message) {
if(isDebugEnabled()){
android.util.Log.d(TAG, name + " " + message);
}
}
@Override
public void trace(Object message, Throwable t) {
if (isTraceEnabled()) {
android.util.Log.d(TAG, name + " " + message, t);
}
}
@Override
public void debug(Object message, Throwable t) {
if(isDebugEnabled()){
android.util.Log.d(TAG, name + " " + message, t);
}
}
@Override
public void debug(Object message) {
if (isDebugEnabled()) {
android.util.Log.d(TAG, name + " " + message);
}
}
@Override
public void error(Object message) {
if(isErrorEnabled()){
android.util.Log.e(TAG, name + " " + message);
}
}
@Override
public void debug(Object message, Throwable t) {
if (isDebugEnabled()) {
android.util.Log.d(TAG, name + " " + message, t);
}
}
@Override
public void error(Object message, Throwable t) {
if(isErrorEnabled()){
android.util.Log.e(TAG, name + " " + message, t);
}
}
@Override
public void error(Object message) {
if (isErrorEnabled()) {
android.util.Log.e(TAG, name + " " + message);
}
}
@Override
public void fatal(Object message) {
if(isFatalEnabled()){
android.util.Log.e(TAG, name + " " + message);
}
@Override
public void error(Object message, Throwable t) {
if (isErrorEnabled()) {
android.util.Log.e(TAG, name + " " + message, t);
}
}
}
@Override
public void fatal(Object message) {
if (isFatalEnabled()) {
android.util.Log.e(TAG, name + " " + message);
}
@Override
public void fatal(Object message, Throwable t) {
if(isFatalEnabled()){
android.util.Log.e(TAG, name + " " + message, t);
}
}
}
@Override
public void info(Object message) {
if(isInfoEnabled()){
android.util.Log.i(TAG, name + " " + message);
}
}
@Override
public void fatal(Object message, Throwable t) {
if (isFatalEnabled()) {
android.util.Log.e(TAG, name + " " + message, t);
}
}
@Override
public void info(Object message, Throwable t) {
if(isInfoEnabled()){
android.util.Log.i(TAG, name + " " + message, t);
}
}
@Override
public void info(Object message) {
if (isInfoEnabled()) {
android.util.Log.i(TAG, name + " " + message);
}
}
@Override
public boolean isTraceEnabled() {
return android.util.Log.isLoggable(TAG, android.util.Log.VERBOSE);
}
@Override
public void info(Object message, Throwable t) {
if (isInfoEnabled()) {
android.util.Log.i(TAG, name + " " + message, t);
}
}
@Override
public boolean isTraceEnabled() {
return android.util.Log.isLoggable(TAG, android.util.Log.VERBOSE);
}
@Override
public boolean isDebugEnabled() {
// For debug purposes always true
// return android.util.Log.isLoggable(TAG, android.util.Log.DEBUG);
return true;
}
@Override
public boolean isDebugEnabled() {
// For debug purposes always true
// return android.util.Log.isLoggable(TAG, android.util.Log.DEBUG);
return true;
}
@Override
public boolean isErrorEnabled() {
return android.util.Log.isLoggable(TAG, android.util.Log.ERROR);
}
@Override
public boolean isErrorEnabled() {
return android.util.Log.isLoggable(TAG, android.util.Log.ERROR);
}
@Override
public boolean isFatalEnabled() {
return android.util.Log.isLoggable(TAG, android.util.Log.ERROR);
}
@Override
public boolean isFatalEnabled() {
return android.util.Log.isLoggable(TAG, android.util.Log.ERROR);
}
@Override
public boolean isInfoEnabled() {
return android.util.Log.isLoggable(TAG, android.util.Log.INFO);
}
@Override
public boolean isInfoEnabled() {
return android.util.Log.isLoggable(TAG, android.util.Log.INFO);
}
@Override
public boolean isWarnEnabled() {
return android.util.Log.isLoggable(TAG, android.util.Log.WARN);
}
@Override
public boolean isWarnEnabled() {
return android.util.Log.isLoggable(TAG, android.util.Log.WARN);
}
@Override
public void warn(Object message) {
if (isWarnEnabled()) {
android.util.Log.w(TAG, name + " " + message);
}
}
@Override
public void warn(Object message) {
if(isWarnEnabled()){
android.util.Log.w(TAG, name + " " + message);
}
}
@Override
public void warn(Object message, Throwable t) {
if (isWarnEnabled()) {
android.util.Log.w(TAG, name + " " + message, t);
}
}
}
@Override
public void warn(Object message, Throwable t) {
if(isWarnEnabled()){
android.util.Log.w(TAG, name + " " + message, t);
}
}
}
public static Log getLog(String name) {
return new OsmandLogImplementation(name);
}
public static Log getLog(String name){
return new OsmandLogImplementation(name);
}
public static Log getLog(Class<?> cl){
return getLog(cl.getName());
}
public static Log getLog(Class<?> cl) {
return getLog(cl.getName());
}
}

View file

@ -17,182 +17,182 @@ import net.osmand.PlatformUtil
class LoginDialogFragment : DialogFragment() {
companion object {
companion object {
private const val TAG = "LoginDialogFragment"
private val LOG = PlatformUtil.getLog(LoginDialogFragment::class.java)
private const val TAG = "LoginDialogFragment"
private val LOG = PlatformUtil.getLog(LoginDialogFragment::class.java)
private const val ENTER_PHONE_NUMBER_PARAM_KEY: String = "enter_phone_number_param_key"
private const val ENTER_CODE_PARAM_KEY = "enter_code_param_key"
private const val ENTER_PASSWORD_PARAM_KEY = "enter_password_param_key"
private const val SHOW_PROGRESS_PARAM_KEY = "show_progress_param_key"
private const val ENTER_PHONE_NUMBER_PARAM_KEY: String = "enter_phone_number_param_key"
private const val ENTER_CODE_PARAM_KEY = "enter_code_param_key"
private const val ENTER_PASSWORD_PARAM_KEY = "enter_password_param_key"
private const val SHOW_PROGRESS_PARAM_KEY = "show_progress_param_key"
fun showDialog(fragmentManager: FragmentManager, vararg loginDialogType: LoginDialogType) {
try {
var fragment = getFragment(fragmentManager)
if (fragment == null) {
fragment = LoginDialogFragment()
val args = Bundle()
for (t in loginDialogType) {
args.putBoolean(t.paramKey, true)
}
fragment.arguments = args
fragment.show(fragmentManager, TAG)
} else {
fragment.updateDialog(*loginDialogType)
}
} catch (e: RuntimeException) {
LOG.error(e)
}
}
fun showDialog(fragmentManager: FragmentManager, vararg loginDialogType: LoginDialogType) {
try {
var fragment = getFragment(fragmentManager)
if (fragment == null) {
fragment = LoginDialogFragment()
val args = Bundle()
for (t in loginDialogType) {
args.putBoolean(t.paramKey, true)
}
fragment.arguments = args
fragment.show(fragmentManager, TAG)
} else {
fragment.updateDialog(*loginDialogType)
}
} catch (e: RuntimeException) {
LOG.error(e)
}
}
fun dismiss(fragmentManager: FragmentManager) {
val loginDialogFragment = getFragment(fragmentManager)
loginDialogFragment?.dismissedManually = true
loginDialogFragment?.dismiss()
}
fun dismiss(fragmentManager: FragmentManager) {
val loginDialogFragment = getFragment(fragmentManager)
loginDialogFragment?.dismissedManually = true
loginDialogFragment?.dismiss()
}
private fun getFragment(fragmentManager: FragmentManager): LoginDialogFragment? {
return fragmentManager.findFragmentByTag(TAG) as LoginDialogFragment?
}
}
private fun getFragment(fragmentManager: FragmentManager): LoginDialogFragment? {
return fragmentManager.findFragmentByTag(TAG) as LoginDialogFragment?
}
}
private var loginDialogActiveTypes: Set<LoginDialogType>? = null
private var loginDialogActiveTypes: Set<LoginDialogType>? = null
private var dismissedManually = false
private var dismissedManually = false
enum class LoginDialogType(val paramKey: String, val viewId: Int, val editorId: Int) {
ENTER_PHONE_NUMBER(ENTER_PHONE_NUMBER_PARAM_KEY, R.id.enterPhoneNumberLayout, R.id.phoneNumberEditText),
ENTER_CODE(ENTER_CODE_PARAM_KEY, R.id.enterCodeLayout, R.id.codeEditText),
ENTER_PASSWORD(ENTER_PASSWORD_PARAM_KEY, R.id.enterPasswordLayout, R.id.passwordEditText),
SHOW_PROGRESS(SHOW_PROGRESS_PARAM_KEY, R.id.progressLayout, 0);
}
enum class LoginDialogType(val paramKey: String, val viewId: Int, val editorId: Int) {
ENTER_PHONE_NUMBER(ENTER_PHONE_NUMBER_PARAM_KEY, R.id.enterPhoneNumberLayout, R.id.phoneNumberEditText),
ENTER_CODE(ENTER_CODE_PARAM_KEY, R.id.enterCodeLayout, R.id.codeEditText),
ENTER_PASSWORD(ENTER_PASSWORD_PARAM_KEY, R.id.enterPasswordLayout, R.id.passwordEditText),
SHOW_PROGRESS(SHOW_PROGRESS_PARAM_KEY, R.id.progressLayout, 0);
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setStyle(DialogFragment.STYLE_NO_FRAME, R.style.AppTheme_NoActionbar)
val activity = requireActivity()
val window = activity.window
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setStyle(DialogFragment.STYLE_NO_FRAME, R.style.AppTheme_NoActionbar)
val activity = requireActivity()
val window = activity.window
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val loginDialogActiveTypes: MutableSet<LoginDialogType> = HashSet()
val loginDialogActiveTypes: MutableSet<LoginDialogType> = HashSet()
val args = savedInstanceState ?: arguments
if (args != null) {
for (t in LoginDialogType.values()) {
if (args.getBoolean(t.paramKey, false)) {
loginDialogActiveTypes.add(t)
}
}
}
val args = savedInstanceState ?: arguments
if (args != null) {
for (t in LoginDialogType.values()) {
if (args.getBoolean(t.paramKey, false)) {
loginDialogActiveTypes.add(t)
}
}
}
this.loginDialogActiveTypes = loginDialogActiveTypes
this.loginDialogActiveTypes = loginDialogActiveTypes
val view = inflater.inflate(R.layout.login_dialog, container)
buildDialog(view)
return view
}
val view = inflater.inflate(R.layout.login_dialog, container)
buildDialog(view)
return view
}
override fun onDismiss(dialog: DialogInterface?) {
super.onDismiss(dialog)
if (!dismissedManually) {
getMainActivity()?.closeTelegram()
}
}
override fun onDismiss(dialog: DialogInterface?) {
super.onDismiss(dialog)
if (!dismissedManually) {
getMainActivity()?.closeTelegram()
}
}
private fun buildDialog(view: View?) {
val loginDialogActiveTypes = this.loginDialogActiveTypes
var hasProgress = false
var focusRequested = false
for (t in LoginDialogType.values()) {
val layout: View? = view?.findViewById(t.viewId)
val contains = loginDialogActiveTypes?.contains(t) ?: false
when {
contains -> {
if (t == LoginDialogType.SHOW_PROGRESS) {
hasProgress = true
}
if (layout != null) {
layout.visibility = View.VISIBLE
val editText: EditText? = layout.findViewById(t.editorId)
if (editText != null) {
editText.setOnEditorActionListener { _, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_DONE) {
applyAuthParam(t, editText.text.toString())
return@setOnEditorActionListener true
}
false
}
if (!focusRequested) {
editText.requestFocus()
AndroidUtils.softKeyboardDelayed(editText)
focusRequested = true
}
}
}
}
else -> layout?.visibility = View.GONE
}
}
val continueButton: Button? = view?.findViewById(R.id.continueButton)
if (continueButton != null) {
continueButton.isEnabled = !hasProgress
if (hasProgress) {
continueButton.setOnClickListener(null)
} else {
continueButton.setOnClickListener {
for (t in LoginDialogType.values()) {
val layout: View? = view.findViewById(t.viewId)
val contains = loginDialogActiveTypes?.contains(t) ?: false
if (contains && layout != null) {
val editText: EditText? = layout.findViewById(t.editorId)
if (editText != null) {
applyAuthParam(t, editText.text.toString())
}
}
}
}
}
}
val cancelButton: Button? = view?.findViewById(R.id.calcelButton)
cancelButton?.setOnClickListener {
dismiss()
}
}
private fun buildDialog(view: View?) {
val loginDialogActiveTypes = this.loginDialogActiveTypes
var hasProgress = false
var focusRequested = false
for (t in LoginDialogType.values()) {
val layout: View? = view?.findViewById(t.viewId)
val contains = loginDialogActiveTypes?.contains(t) ?: false
when {
contains -> {
if (t == LoginDialogType.SHOW_PROGRESS) {
hasProgress = true
}
if (layout != null) {
layout.visibility = View.VISIBLE
val editText: EditText? = layout.findViewById(t.editorId)
if (editText != null) {
editText.setOnEditorActionListener { _, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_DONE) {
applyAuthParam(t, editText.text.toString())
return@setOnEditorActionListener true
}
false
}
if (!focusRequested) {
editText.requestFocus()
AndroidUtils.softKeyboardDelayed(editText)
focusRequested = true
}
}
}
}
else -> layout?.visibility = View.GONE
}
}
val continueButton: Button? = view?.findViewById(R.id.continueButton)
if (continueButton != null) {
continueButton.isEnabled = !hasProgress
if (hasProgress) {
continueButton.setOnClickListener(null)
} else {
continueButton.setOnClickListener {
for (t in LoginDialogType.values()) {
val layout: View? = view.findViewById(t.viewId)
val contains = loginDialogActiveTypes?.contains(t) ?: false
if (contains && layout != null) {
val editText: EditText? = layout.findViewById(t.editorId)
if (editText != null) {
applyAuthParam(t, editText.text.toString())
}
}
}
}
}
}
val cancelButton: Button? = view?.findViewById(R.id.calcelButton)
cancelButton?.setOnClickListener {
dismiss()
}
}
private fun applyAuthParam(t: LoginDialogType, value: String) {
getMainActivity()?.applyAuthParam(this, t, value)
}
private fun applyAuthParam(t: LoginDialogType, value: String) {
getMainActivity()?.applyAuthParam(this, t, value)
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
val loginDialogActiveTypes = this.loginDialogActiveTypes
if (loginDialogActiveTypes != null) {
for (t in loginDialogActiveTypes) {
outState.putBoolean(t.paramKey, true)
}
}
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
val loginDialogActiveTypes = this.loginDialogActiveTypes
if (loginDialogActiveTypes != null) {
for (t in loginDialogActiveTypes) {
outState.putBoolean(t.paramKey, true)
}
}
}
private fun getMainActivity(): MainActivity? {
val activity = this.activity
return if (activity != null) {
activity as MainActivity
} else {
null
}
}
private fun getMainActivity(): MainActivity? {
val activity = this.activity
return if (activity != null) {
activity as MainActivity
} else {
null
}
}
fun updateDialog(vararg loginDialogType: LoginDialogType) {
val loginDialogActiveTypes: MutableSet<LoginDialogType> = HashSet()
for (t in loginDialogType) {
loginDialogActiveTypes.add(t)
}
this.loginDialogActiveTypes = loginDialogActiveTypes
fun updateDialog(vararg loginDialogType: LoginDialogType) {
val loginDialogActiveTypes: MutableSet<LoginDialogType> = HashSet()
for (t in loginDialogType) {
loginDialogActiveTypes.add(t)
}
this.loginDialogActiveTypes = loginDialogActiveTypes
buildDialog(view)
}
buildDialog(view)
}
}

View file

@ -23,370 +23,376 @@ import org.drinkless.td.libcore.telegram.TdApi
class MainActivity : AppCompatActivity(), TelegramListener {
companion object {
private const val PERMISSION_REQUEST_LOCATION = 1
companion object {
private const val PERMISSION_REQUEST_LOCATION = 1
private const val LOGIN_MENU_ID = 0
private const val LOGOUT_MENU_ID = 1
private const val PROGRESS_MENU_ID = 2
}
private const val LOGIN_MENU_ID = 0
private const val LOGOUT_MENU_ID = 1
private const val PROGRESS_MENU_ID = 2
}
private val log = PlatformUtil.getLog(TelegramHelper::class.java)
private val log = PlatformUtil.getLog(TelegramHelper::class.java)
private var telegramAuthorizationRequestHandler: TelegramAuthorizationRequestHandler? = null
private var paused: Boolean = false
private var telegramAuthorizationRequestHandler: TelegramAuthorizationRequestHandler? = null
private var paused: Boolean = false
private lateinit var chatsView: RecyclerView
private lateinit var chatViewAdapter: ChatsAdapter
private lateinit var chatViewManager: RecyclerView.LayoutManager
private lateinit var chatsView: RecyclerView
private lateinit var chatViewAdapter: ChatsAdapter
private lateinit var chatViewManager: RecyclerView.LayoutManager
private val app: TelegramApplication
get() = application as TelegramApplication
private val app: TelegramApplication
get() = application as TelegramApplication
private val telegramHelper get() = app.telegramHelper
private val osmandHelper get() = app.osmandHelper
private val settings get() = app.settings
private val telegramHelper get() = app.telegramHelper
private val osmandHelper get() = app.osmandHelper
private val settings get() = app.settings
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
paused = false
paused = false
chatViewManager = LinearLayoutManager(this)
chatViewAdapter = ChatsAdapter()
chatViewManager = LinearLayoutManager(this)
chatViewAdapter = ChatsAdapter()
chatsView = findViewById<RecyclerView>(R.id.groups_view).apply {
//setHasFixedSize(true)
chatsView = findViewById<RecyclerView>(R.id.groups_view).apply {
//setHasFixedSize(true)
// use a linear layout manager
layoutManager = chatViewManager
// use a linear layout manager
layoutManager = chatViewManager
// specify an viewAdapter (see also next example)
adapter = chatViewAdapter
// specify an viewAdapter (see also next example)
adapter = chatViewAdapter
}
}
telegramAuthorizationRequestHandler = telegramHelper.setTelegramAuthorizationRequestHandler(object : TelegramAuthorizationRequestListener {
override fun onRequestTelegramAuthenticationParameter(parameterType: TelegramAuthenticationParameterType) {
runOnUi {
showLoginDialog(parameterType)
}
}
telegramAuthorizationRequestHandler = telegramHelper.setTelegramAuthorizationRequestHandler(object : TelegramAuthorizationRequestListener {
override fun onRequestTelegramAuthenticationParameter(parameterType: TelegramAuthenticationParameterType) {
runOnUi {
showLoginDialog(parameterType)
}
}
override fun onTelegramAuthorizationRequestError(code: Int, message: String) {
runOnUi {
Toast.makeText(this@MainActivity, "$code - $message", Toast.LENGTH_LONG).show()
}
}
})
telegramHelper.listener = this
telegramHelper.init()
}
override fun onTelegramAuthorizationRequestError(code: Int, message: String) {
runOnUi {
Toast.makeText(this@MainActivity, "$code - $message", Toast.LENGTH_LONG).show()
}
}
})
telegramHelper.listener = this
telegramHelper.init()
}
override fun onResume() {
super.onResume()
paused = false
override fun onResume() {
super.onResume()
paused = false
invalidateOptionsMenu()
updateTitle()
invalidateOptionsMenu()
updateTitle()
if (settings.hasAnyChatToShareLocation() && !AndroidUtils.isLocationPermissionAvailable(this)) {
requestLocationPermission()
} else if (settings.hasAnyChatToShowOnMap() && osmandHelper.initialized && !osmandHelper.isOsmandBound()) {
showOsmandMissingDialog()
}
}
if (settings.hasAnyChatToShareLocation() && !AndroidUtils.isLocationPermissionAvailable(this)) {
requestLocationPermission()
} else if (settings.hasAnyChatToShowOnMap() && osmandHelper.initialized && !osmandHelper.isOsmandBound()) {
showOsmandMissingDialog()
}
}
override fun onPause() {
super.onPause()
paused = true
}
override fun onPause() {
super.onPause()
paused = true
}
override fun onStop() {
super.onStop()
settings.save()
}
override fun onStop() {
super.onStop()
settings.save()
}
override fun onTelegramStatusChanged(prevTelegramAuthorizationState: TelegramAuthorizationState,
newTelegramAuthorizationState: TelegramAuthorizationState) {
runOnUi {
val fm = supportFragmentManager
when (newTelegramAuthorizationState) {
TelegramAuthorizationState.READY,
TelegramAuthorizationState.CLOSED,
TelegramAuthorizationState.UNKNOWN -> LoginDialogFragment.dismiss(fm)
else -> Unit
}
invalidateOptionsMenu()
updateTitle()
override fun onDestroy() {
super.onDestroy()
when (newTelegramAuthorizationState) {
TelegramAuthorizationState.READY -> {
updateChatsList()
}
TelegramAuthorizationState.CLOSED,
TelegramAuthorizationState.UNKNOWN -> {
chatViewAdapter.chats = emptyList()
}
else -> Unit
}
}
}
app.cleanupResources()
}
override fun onTelegramChatsRead() {
runOnUi {
removeNonexistingChatsFromSettings()
updateChatsList()
}
}
override fun onTelegramStatusChanged(prevTelegramAuthorizationState: TelegramAuthorizationState,
newTelegramAuthorizationState: TelegramAuthorizationState) {
runOnUi {
val fm = supportFragmentManager
when (newTelegramAuthorizationState) {
TelegramAuthorizationState.READY,
TelegramAuthorizationState.CLOSED,
TelegramAuthorizationState.UNKNOWN -> LoginDialogFragment.dismiss(fm)
else -> Unit
}
invalidateOptionsMenu()
updateTitle()
override fun onTelegramChatsChanged() {
runOnUi {
updateChatsList()
}
}
when (newTelegramAuthorizationState) {
TelegramAuthorizationState.READY -> {
updateChatsList()
}
TelegramAuthorizationState.CLOSED,
TelegramAuthorizationState.UNKNOWN -> {
chatViewAdapter.chats = emptyList()
}
else -> Unit
}
}
}
override fun onTelegramError(code: Int, message: String) {
runOnUi {
Toast.makeText(this@MainActivity, "$code - $message", Toast.LENGTH_LONG).show()
}
}
override fun onTelegramChatsRead() {
runOnUi {
removeNonexistingChatsFromSettings()
updateChatsList()
}
}
override fun onSendLiveLicationError(code: Int, message: String) {
log.error("Send live location error: $code - $message")
app.isInternetConnectionAvailable(true)
}
override fun onTelegramChatsChanged() {
runOnUi {
updateChatsList()
}
}
private fun removeNonexistingChatsFromSettings() {
val presentChatTitles = telegramHelper.getChatTitles()
settings.removeNonexistingChats(presentChatTitles)
}
override fun onTelegramError(code: Int, message: String) {
runOnUi {
Toast.makeText(this@MainActivity, "$code - $message", Toast.LENGTH_LONG).show()
}
}
private fun updateChatsList() {
val chatList = telegramHelper.getChatList()
val chats: MutableList<TdApi.Chat> = mutableListOf()
for (orderedChat in chatList) {
val chat = telegramHelper.getChat(orderedChat.chatId)
if (chat != null) {
chats.add(chat)
}
}
chatViewAdapter.chats = chats
}
override fun onSendLiveLicationError(code: Int, message: String) {
log.error("Send live location error: $code - $message")
app.isInternetConnectionAvailable(true)
}
fun logoutTelegram(silent: Boolean = false) {
if (telegramHelper.getTelegramAuthorizationState() == TelegramAuthorizationState.READY) {
telegramHelper.logout()
} else {
invalidateOptionsMenu()
updateTitle()
if (!silent) {
Toast.makeText(this, R.string.not_logged_in, Toast.LENGTH_SHORT).show()
}
}
}
private fun removeNonexistingChatsFromSettings() {
val presentChatTitles = telegramHelper.getChatTitles()
settings.removeNonexistingChats(presentChatTitles)
}
fun closeTelegram() {
telegramHelper.close()
}
private fun updateChatsList() {
val chatList = telegramHelper.getChatList()
val chats: MutableList<TdApi.Chat> = mutableListOf()
for (orderedChat in chatList) {
val chat = telegramHelper.getChat(orderedChat.chatId)
if (chat != null) {
chats.add(chat)
}
}
chatViewAdapter.chats = chats
}
private fun runOnUi(action: (() -> Unit)) {
if (!paused) {
runOnUiThread(action)
}
}
fun logoutTelegram(silent: Boolean = false) {
if (telegramHelper.getTelegramAuthorizationState() == TelegramAuthorizationState.READY) {
telegramHelper.logout()
} else {
invalidateOptionsMenu()
updateTitle()
if (!silent) {
Toast.makeText(this, R.string.not_logged_in, Toast.LENGTH_SHORT).show()
}
}
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
return when (item?.itemId) {
LOGIN_MENU_ID -> {
telegramHelper.init()
true
}
LOGOUT_MENU_ID -> {
logoutTelegram()
true
}
else -> super.onOptionsItemSelected(item)
}
}
fun closeTelegram() {
telegramHelper.close()
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
if (menu != null) {
menu.clear()
when (telegramHelper.getTelegramAuthorizationState()) {
TelegramAuthorizationState.UNKNOWN,
TelegramAuthorizationState.WAIT_PARAMETERS,
TelegramAuthorizationState.WAIT_PHONE_NUMBER,
TelegramAuthorizationState.WAIT_CODE,
TelegramAuthorizationState.WAIT_PASSWORD,
TelegramAuthorizationState.LOGGING_OUT,
TelegramAuthorizationState.CLOSING -> createProgressMenuItem(menu)
TelegramAuthorizationState.READY -> createMenuItem(menu, LOGOUT_MENU_ID, R.string.shared_string_logout,
MenuItem.SHOW_AS_ACTION_WITH_TEXT or MenuItem.SHOW_AS_ACTION_ALWAYS)
TelegramAuthorizationState.CLOSED -> createMenuItem(menu, LOGIN_MENU_ID, R.string.shared_string_login,
MenuItem.SHOW_AS_ACTION_WITH_TEXT or MenuItem.SHOW_AS_ACTION_ALWAYS)
}
}
return super.onCreateOptionsMenu(menu)
}
private fun runOnUi(action: (() -> Unit)) {
if (!paused) {
runOnUiThread(action)
}
}
private fun createMenuItem(m: Menu, id: Int, titleRes: Int, menuItemType: Int): MenuItem {
val menuItem = m.add(0, id, 0, titleRes)
menuItem.setOnMenuItemClickListener { item -> onOptionsItemSelected(item) }
menuItem.setShowAsAction(menuItemType)
return menuItem
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
return when (item?.itemId) {
LOGIN_MENU_ID -> {
telegramHelper.init()
true
}
LOGOUT_MENU_ID -> {
logoutTelegram()
true
}
else -> super.onOptionsItemSelected(item)
}
}
private fun createProgressMenuItem(m: Menu): MenuItem {
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
if (menu != null) {
menu.clear()
when (telegramHelper.getTelegramAuthorizationState()) {
TelegramAuthorizationState.UNKNOWN,
TelegramAuthorizationState.WAIT_PARAMETERS,
TelegramAuthorizationState.WAIT_PHONE_NUMBER,
TelegramAuthorizationState.WAIT_CODE,
TelegramAuthorizationState.WAIT_PASSWORD,
TelegramAuthorizationState.LOGGING_OUT,
TelegramAuthorizationState.CLOSING -> createProgressMenuItem(menu)
TelegramAuthorizationState.READY -> createMenuItem(menu, LOGOUT_MENU_ID, R.string.shared_string_logout,
MenuItem.SHOW_AS_ACTION_WITH_TEXT or MenuItem.SHOW_AS_ACTION_ALWAYS)
TelegramAuthorizationState.CLOSED -> createMenuItem(menu, LOGIN_MENU_ID, R.string.shared_string_login,
MenuItem.SHOW_AS_ACTION_WITH_TEXT or MenuItem.SHOW_AS_ACTION_ALWAYS)
}
}
return super.onCreateOptionsMenu(menu)
}
val menuItem = m.add(0, PROGRESS_MENU_ID, 0, "")
menuItem.actionView = layoutInflater.inflate(R.layout.action_progress_bar, null)
menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS)
return menuItem
}
private fun createMenuItem(m: Menu, id: Int, titleRes: Int, menuItemType: Int): MenuItem {
val menuItem = m.add(0, id, 0, titleRes)
menuItem.setOnMenuItemClickListener { item -> onOptionsItemSelected(item) }
menuItem.setShowAsAction(menuItemType)
return menuItem
}
private fun updateTitle() {
title = when (telegramHelper.getTelegramAuthorizationState()) {
private fun createProgressMenuItem(m: Menu): MenuItem {
TelegramAuthorizationState.UNKNOWN,
TelegramAuthorizationState.WAIT_PHONE_NUMBER,
TelegramAuthorizationState.WAIT_CODE,
TelegramAuthorizationState.WAIT_PASSWORD,
TelegramAuthorizationState.READY,
TelegramAuthorizationState.CLOSED -> getString(R.string.app_name)
val menuItem = m.add(0, PROGRESS_MENU_ID, 0, "")
menuItem.actionView = layoutInflater.inflate(R.layout.action_progress_bar, null)
menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS)
return menuItem
}
TelegramAuthorizationState.WAIT_PARAMETERS -> getString(R.string.initialization) + "..."
TelegramAuthorizationState.LOGGING_OUT -> getString(R.string.logging_out) + "..."
TelegramAuthorizationState.CLOSING -> getString(R.string.closing) + "..."
}
}
private fun updateTitle() {
title = when (telegramHelper.getTelegramAuthorizationState()) {
private fun showLoginDialog(telegramAuthenticationParameterType: TelegramAuthenticationParameterType) {
when (telegramAuthenticationParameterType) {
TelegramAuthenticationParameterType.PHONE_NUMBER -> LoginDialogFragment.showDialog(supportFragmentManager, LoginDialogType.ENTER_PHONE_NUMBER)
TelegramAuthenticationParameterType.CODE -> LoginDialogFragment.showDialog(supportFragmentManager, LoginDialogType.ENTER_CODE)
TelegramAuthenticationParameterType.PASSWORD -> LoginDialogFragment.showDialog(supportFragmentManager, LoginDialogType.ENTER_PASSWORD)
}
}
TelegramAuthorizationState.UNKNOWN,
TelegramAuthorizationState.WAIT_PHONE_NUMBER,
TelegramAuthorizationState.WAIT_CODE,
TelegramAuthorizationState.WAIT_PASSWORD,
TelegramAuthorizationState.READY,
TelegramAuthorizationState.CLOSED -> getString(R.string.app_name)
fun applyAuthParam(loginDialogFragment: LoginDialogFragment?, loginDialogType: LoginDialogType, text: String) {
loginDialogFragment?.updateDialog(LoginDialogType.SHOW_PROGRESS)
when (loginDialogType) {
LoginDialogType.ENTER_PHONE_NUMBER -> telegramAuthorizationRequestHandler?.applyAuthenticationParameter(TelegramAuthenticationParameterType.PHONE_NUMBER, text)
LoginDialogType.ENTER_CODE -> telegramAuthorizationRequestHandler?.applyAuthenticationParameter(TelegramAuthenticationParameterType.CODE, text)
LoginDialogType.ENTER_PASSWORD -> telegramAuthorizationRequestHandler?.applyAuthenticationParameter(TelegramAuthenticationParameterType.PASSWORD, text)
else -> Unit
}
}
TelegramAuthorizationState.WAIT_PARAMETERS -> getString(R.string.initialization) + "..."
TelegramAuthorizationState.LOGGING_OUT -> getString(R.string.logging_out) + "..."
TelegramAuthorizationState.CLOSING -> getString(R.string.closing) + "..."
}
}
private fun requestLocationPermission() {
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), PERMISSION_REQUEST_LOCATION)
}
private fun showLoginDialog(telegramAuthenticationParameterType: TelegramAuthenticationParameterType) {
when (telegramAuthenticationParameterType) {
TelegramAuthenticationParameterType.PHONE_NUMBER -> LoginDialogFragment.showDialog(supportFragmentManager, LoginDialogType.ENTER_PHONE_NUMBER)
TelegramAuthenticationParameterType.CODE -> LoginDialogFragment.showDialog(supportFragmentManager, LoginDialogType.ENTER_CODE)
TelegramAuthenticationParameterType.PASSWORD -> LoginDialogFragment.showDialog(supportFragmentManager, LoginDialogType.ENTER_PASSWORD)
}
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
when (requestCode) {
PERMISSION_REQUEST_LOCATION -> {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (settings.hasAnyChatToShareLocation()) {
app.shareLocationHelper.startSharingLocation()
}
}
if (settings.hasAnyChatToShowOnMap() && osmandHelper.initialized && !osmandHelper.isOsmandBound()) {
showOsmandMissingDialog()
}
}
}
}
fun applyAuthParam(loginDialogFragment: LoginDialogFragment?, loginDialogType: LoginDialogType, text: String) {
loginDialogFragment?.updateDialog(LoginDialogType.SHOW_PROGRESS)
when (loginDialogType) {
LoginDialogType.ENTER_PHONE_NUMBER -> telegramAuthorizationRequestHandler?.applyAuthenticationParameter(TelegramAuthenticationParameterType.PHONE_NUMBER, text)
LoginDialogType.ENTER_CODE -> telegramAuthorizationRequestHandler?.applyAuthenticationParameter(TelegramAuthenticationParameterType.CODE, text)
LoginDialogType.ENTER_PASSWORD -> telegramAuthorizationRequestHandler?.applyAuthenticationParameter(TelegramAuthenticationParameterType.PASSWORD, text)
else -> Unit
}
}
fun showOsmandMissingDialog() {
OsmandMissingDialogFragment().show(supportFragmentManager, null)
}
private fun requestLocationPermission() {
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), PERMISSION_REQUEST_LOCATION)
}
class OsmandMissingDialogFragment : DialogFragment() {
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
when (requestCode) {
PERMISSION_REQUEST_LOCATION -> {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (settings.hasAnyChatToShareLocation()) {
app.shareLocationHelper.startSharingLocation()
}
}
if (settings.hasAnyChatToShowOnMap() && osmandHelper.initialized && !osmandHelper.isOsmandBound()) {
showOsmandMissingDialog()
}
}
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = AlertDialog.Builder(requireContext())
builder.setView(R.layout.install_osmand_dialog)
.setNegativeButton("Cancel", null)
.setPositiveButton("Install", { _, _ ->
val intent = Intent()
intent.data = Uri.parse("market://details?id=net.osmand.plus")
startActivity(intent)
})
return builder.create()
}
}
fun showOsmandMissingDialog() {
OsmandMissingDialogFragment().show(supportFragmentManager, null)
}
inner class ChatsAdapter :
RecyclerView.Adapter<ChatsAdapter.ViewHolder>() {
class OsmandMissingDialogFragment : DialogFragment() {
var chats: List<TdApi.Chat> = emptyList()
set(value) {
field = value
notifyDataSetChanged()
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = AlertDialog.Builder(requireContext())
builder.setView(R.layout.install_osmand_dialog)
.setNegativeButton("Cancel", null)
.setPositiveButton("Install", { _, _ ->
val intent = Intent()
intent.data = Uri.parse("market://details?id=net.osmand.plus")
startActivity(intent)
})
return builder.create()
}
}
inner class ViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
val icon: AppCompatImageView? = view.findViewById(R.id.icon)
val groupName: AppCompatTextView? = view.findViewById(R.id.name)
val shareLocationSwitch: SwitchCompat? = view.findViewById(R.id.share_location_switch)
val showOnMapSwitch: SwitchCompat? = view.findViewById(R.id.show_on_map_switch)
}
inner class ChatsAdapter :
RecyclerView.Adapter<ChatsAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ChatsAdapter.ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.chat_list_item, parent, false)
return ViewHolder(view)
}
var chats: List<TdApi.Chat> = emptyList()
set(value) {
field = value
notifyDataSetChanged()
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val chatTitle = chats[position].title
holder.groupName?.text = chatTitle
inner class ViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
val icon: AppCompatImageView? = view.findViewById(R.id.icon)
val groupName: AppCompatTextView? = view.findViewById(R.id.name)
val shareLocationSwitch: SwitchCompat? = view.findViewById(R.id.share_location_switch)
val showOnMapSwitch: SwitchCompat? = view.findViewById(R.id.show_on_map_switch)
}
holder.shareLocationSwitch?.setOnCheckedChangeListener(null)
holder.shareLocationSwitch?.isChecked = settings.isSharingLocationToChat(chatTitle)
holder.shareLocationSwitch?.setOnCheckedChangeListener { view, isChecked ->
settings.shareLocationToChat(chatTitle, isChecked)
if (settings.hasAnyChatToShareLocation()) {
if (!AndroidUtils.isLocationPermissionAvailable(view.context)) {
if (isChecked) {
requestLocationPermission()
}
} else {
app.shareLocationHelper.startSharingLocation()
}
} else {
app.shareLocationHelper.stopSharingLocation()
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ChatsAdapter.ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.chat_list_item, parent, false)
return ViewHolder(view)
}
holder.showOnMapSwitch?.setOnCheckedChangeListener(null)
holder.showOnMapSwitch?.isChecked = settings.isShowingChatOnMap(chatTitle)
holder.showOnMapSwitch?.setOnCheckedChangeListener { _, isChecked ->
settings.showChatOnMap(chatTitle, isChecked)
if (settings.hasAnyChatToShowOnMap()) {
if (osmandHelper.initialized && !osmandHelper.isOsmandBound()) {
if (isChecked) {
showOsmandMissingDialog()
}
} else {
if (isChecked) {
app.showLocationHelper.showChatMessages(chatTitle)
} else {
app.showLocationHelper.hideChatMessages(chatTitle)
}
app.showLocationHelper.startShowingLocation()
}
} else {
app.showLocationHelper.stopShowingLocation()
if (!isChecked) {
app.showLocationHelper.hideChatMessages(chatTitle)
}
}
}
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val chatTitle = chats[position].title
holder.groupName?.text = chatTitle
override fun getItemCount() = chats.size
}
holder.shareLocationSwitch?.setOnCheckedChangeListener(null)
holder.shareLocationSwitch?.isChecked = settings.isSharingLocationToChat(chatTitle)
holder.shareLocationSwitch?.setOnCheckedChangeListener { view, isChecked ->
settings.shareLocationToChat(chatTitle, isChecked)
if (settings.hasAnyChatToShareLocation()) {
if (!AndroidUtils.isLocationPermissionAvailable(view.context)) {
if (isChecked) {
requestLocationPermission()
}
} else {
app.shareLocationHelper.startSharingLocation()
}
} else {
app.shareLocationHelper.stopSharingLocation()
}
}
holder.showOnMapSwitch?.setOnCheckedChangeListener(null)
holder.showOnMapSwitch?.isChecked = settings.isShowingChatOnMap(chatTitle)
holder.showOnMapSwitch?.setOnCheckedChangeListener { _, isChecked ->
settings.showChatOnMap(chatTitle, isChecked)
if (settings.hasAnyChatToShowOnMap()) {
if (osmandHelper.initialized && !osmandHelper.isOsmandBound()) {
if (isChecked) {
showOsmandMissingDialog()
}
} else {
if (isChecked) {
app.showLocationHelper.showChatMessages(chatTitle)
} else {
app.showLocationHelper.hideChatMessages(chatTitle)
}
app.showLocationHelper.startShowingLocation()
}
} else {
app.showLocationHelper.stopShowingLocation()
if (!isChecked) {
app.showLocationHelper.hideChatMessages(chatTitle)
}
}
}
}
override fun getItemCount() = chats.size
}
}

View file

@ -12,128 +12,117 @@ import net.osmand.telegram.helpers.ShareLocationHelper
import net.osmand.telegram.helpers.ShowLocationHelper
import net.osmand.telegram.helpers.TelegramHelper
import net.osmand.telegram.notifications.NotificationHelper
import net.osmand.telegram.services.MyLocationService
import net.osmand.telegram.services.UserLocationService
import net.osmand.telegram.utils.AndroidUtils
class TelegramApplication : Application() {
val telegramHelper = TelegramHelper.instance
lateinit var settings: TelegramSettings private set
lateinit var shareLocationHelper: ShareLocationHelper private set
lateinit var showLocationHelper: ShowLocationHelper private set
lateinit var notificationHelper: NotificationHelper private set
lateinit var osmandHelper: OsmandAidlHelper private set
val telegramHelper = TelegramHelper.instance
lateinit var settings: TelegramSettings private set
lateinit var shareLocationHelper: ShareLocationHelper private set
lateinit var showLocationHelper: ShowLocationHelper private set
lateinit var notificationHelper: NotificationHelper private set
lateinit var osmandHelper: OsmandAidlHelper private set
var myLocationService: MyLocationService? = null
var userLocationService: UserLocationService? = null
var telegramService: TelegramService? = null
private val uiHandler = Handler()
private val uiHandler = Handler()
private val lastTimeInternetConnectionChecked: Long = 0
private var internetConnectionAvailable = true
private val lastTimeInternetConnectionChecked: Long = 0
private var internetConnectionAvailable = true
override fun onCreate() {
super.onCreate()
telegramHelper.appDir = filesDir.absolutePath
override fun onCreate() {
super.onCreate()
telegramHelper.appDir = filesDir.absolutePath
settings = TelegramSettings(this)
osmandHelper = OsmandAidlHelper(this)
shareLocationHelper = ShareLocationHelper(this)
showLocationHelper = ShowLocationHelper(this)
notificationHelper = NotificationHelper(this)
settings = TelegramSettings(this)
osmandHelper = OsmandAidlHelper(this)
shareLocationHelper = ShareLocationHelper(this)
showLocationHelper = ShowLocationHelper(this)
notificationHelper = NotificationHelper(this)
if (settings.hasAnyChatToShareLocation() && AndroidUtils.isLocationPermissionAvailable(this)) {
shareLocationHelper.startSharingLocation()
}
if (settings.hasAnyChatToShowOnMap()) {
showLocationHelper.startShowingLocation()
}
}
if (settings.hasAnyChatToShareLocation() && AndroidUtils.isLocationPermissionAvailable(this)) {
shareLocationHelper.startSharingLocation()
}
if (settings.hasAnyChatToShowOnMap()) {
showLocationHelper.startShowingLocation()
}
}
override fun onTerminate() {
super.onTerminate()
// TODO close telegram api in appropriate place
osmandHelper.cleanupResources()
telegramHelper.close()
}
fun cleanupResources() {
osmandHelper.cleanupResources()
telegramHelper.close()
}
val isWifiConnected: Boolean
get() {
val mgr = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val ni = mgr.activeNetworkInfo
return ni != null && ni.type == ConnectivityManager.TYPE_WIFI
}
val isWifiConnected: Boolean
get() {
val mgr = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val ni = mgr.activeNetworkInfo
return ni != null && ni.type == ConnectivityManager.TYPE_WIFI
}
private val isInternetConnected: Boolean
get() {
val mgr = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val active = mgr.activeNetworkInfo
if (active == null) {
return false
} else {
val state = active.state
return state != NetworkInfo.State.DISCONNECTED && state != NetworkInfo.State.DISCONNECTING
}
}
private val isInternetConnected: Boolean
get() {
val mgr = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val active = mgr.activeNetworkInfo
if (active == null) {
return false
} else {
val state = active.state
return state != NetworkInfo.State.DISCONNECTED && state != NetworkInfo.State.DISCONNECTING
}
}
// Check internet connection available every 15 seconds
val isInternetConnectionAvailable: Boolean
get() = isInternetConnectionAvailable(false)
// Check internet connection available every 15 seconds
val isInternetConnectionAvailable: Boolean
get() = isInternetConnectionAvailable(false)
fun isInternetConnectionAvailable(update: Boolean): Boolean {
val delta = System.currentTimeMillis() - lastTimeInternetConnectionChecked
if (delta < 0 || delta > 15000 || update) {
internetConnectionAvailable = isInternetConnected
}
return internetConnectionAvailable
}
fun isInternetConnectionAvailable(update: Boolean): Boolean {
val delta = System.currentTimeMillis() - lastTimeInternetConnectionChecked
if (delta < 0 || delta > 15000 || update) {
internetConnectionAvailable = isInternetConnected
}
return internetConnectionAvailable
}
fun startMyLocationService(restart: Boolean = false) {
val serviceIntent = Intent(this, MyLocationService::class.java)
private fun startTelegramService(intent: Int) {
var i = intent
val serviceIntent = Intent(this, TelegramService::class.java)
val myLocationService = myLocationService
if (myLocationService != null && restart) {
myLocationService.stopSelf()
}
if (myLocationService == null || restart) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(serviceIntent)
} else {
startService(serviceIntent)
}
}
}
val telegramService = telegramService
if (telegramService != null) {
i = intent or telegramService.usedBy
telegramService.stopSelf()
}
fun stopMyLocationService() {
myLocationService?.stopIfNeeded(this)
}
serviceIntent.putExtra(TelegramService.USAGE_INTENT, i)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(serviceIntent)
} else {
startService(serviceIntent)
}
}
fun startUserLocationService(restart: Boolean = false) {
val serviceIntent = Intent(this, UserLocationService::class.java)
fun startMyLocationService() {
startTelegramService(TelegramService.USED_BY_MY_LOCATION)
}
val userLocationService = userLocationService
if (userLocationService != null && restart) {
userLocationService.stopSelf()
}
if (userLocationService == null || restart) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(serviceIntent)
} else {
startService(serviceIntent)
}
}
}
fun stopMyLocationService() {
telegramService?.stopIfNeeded(this, TelegramService.USED_BY_MY_LOCATION)
}
fun stopUserLocationService() {
userLocationService?.stopIfNeeded(this)
}
fun startUserLocationService() {
startTelegramService(TelegramService.USED_BY_USERS_LOCATIONS)
}
fun runInUIThread(action: (() -> Unit)) {
uiHandler.post(action)
}
fun stopUserLocationService() {
telegramService?.stopIfNeeded(this, TelegramService.USED_BY_USERS_LOCATIONS)
}
fun runInUIThread(action: (() -> Unit), delay: Long) {
uiHandler.postDelayed(action, delay)
}
fun runInUIThread(action: (() -> Unit)) {
uiHandler.post(action)
}
fun runInUIThread(action: (() -> Unit), delay: Long) {
uiHandler.postDelayed(action, delay)
}
}

View file

@ -0,0 +1,169 @@
package net.osmand.telegram
import android.app.Service
import android.content.Context
import android.content.Intent
import android.location.Location
import android.location.LocationListener
import android.location.LocationManager
import android.os.*
import android.util.Log
import android.widget.Toast
import net.osmand.PlatformUtil
import net.osmand.telegram.helpers.TelegramHelper.TelegramIncomingMessagesListener
import org.drinkless.td.libcore.telegram.TdApi
import java.util.concurrent.Executors
class TelegramService : Service(), LocationListener, TelegramIncomingMessagesListener {
private fun app() = application as TelegramApplication
private val binder = LocationServiceBinder()
private val executor = Executors.newSingleThreadExecutor()
var handler: Handler? = null
var usedBy = 0
class LocationServiceBinder : Binder()
override fun onBind(intent: Intent): IBinder? {
return binder
}
fun stopIfNeeded(ctx: Context, usageIntent: Int) {
if (usedBy and usageIntent > 0) {
usedBy -= usageIntent
}
if (usedBy == 0) {
val serviceIntent = Intent(ctx, TelegramService::class.java)
ctx.stopService(serviceIntent)
}
}
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
val app = app()
handler = Handler()
usedBy = intent.getIntExtra(USAGE_INTENT, 0)
app.telegramService = this
app.telegramHelper.incomingMessagesListener = this
if (needLocation()) {
// request location updates
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
try {
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0f, this@TelegramService)
} catch (e: SecurityException) {
Toast.makeText(this, R.string.no_location_permission, Toast.LENGTH_LONG).show()
Log.d(PlatformUtil.TAG, "Location service permission not granted")
} catch (e: IllegalArgumentException) {
Toast.makeText(this, R.string.gps_not_available, Toast.LENGTH_LONG).show()
Log.d(PlatformUtil.TAG, "GPS location provider not available")
}
}
val locationNotification = app.notificationHelper.locationNotification
val notification = app.notificationHelper.buildNotification(locationNotification)
startForeground(locationNotification.telegramNotificationId, notification)
app.notificationHelper.refreshNotification(locationNotification.type)
return Service.START_REDELIVER_INTENT
}
override fun onDestroy() {
super.onDestroy()
val app = app()
app.telegramHelper.incomingMessagesListener = null
app.telegramService = null
usedBy = 0
// remove updates
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
try {
locationManager.removeUpdates(this)
} catch (e: SecurityException) {
Log.d(PlatformUtil.TAG, "Location service permission not granted")
}
// remove notification
stopForeground(java.lang.Boolean.TRUE)
}
private fun needLocation(): Boolean {
return (usedBy and USED_BY_MY_LOCATION) > 0
}
override fun onLocationChanged(l: Location?) {
if (l != null) {
val location = convertLocation(l)
app().shareLocationHelper.updateLocation(location)
}
}
override fun onProviderDisabled(provider: String) {
Toast.makeText(this, getString(R.string.location_service_no_gps_available), Toast.LENGTH_LONG).show()
}
override fun onProviderEnabled(provider: String) {}
override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {}
override fun onTaskRemoved(rootIntent: Intent) {
val app = app()
if (app.telegramService != null) {
// Do not stop service after UI task was dismissed
//this@TelegramService.stopSelf()
}
}
override fun onReceiveChatLocationMessages(chatTitle: String, vararg messages: TdApi.Message) {
val app = app()
if (app.settings.isShowingChatOnMap(chatTitle)) {
ShowMessagesTask(app, chatTitle).executeOnExecutor(executor, *messages)
}
}
private class ShowMessagesTask(private val app: TelegramApplication, private val chatTitle: String) : AsyncTask<TdApi.Message, Void, Void?>() {
override fun doInBackground(vararg messages: TdApi.Message): Void? {
for (message in messages) {
app.showLocationHelper.showLocationOnMap(chatTitle, message)
}
return null
}
}
companion object {
const val USED_BY_MY_LOCATION: Int = 1
const val USED_BY_USERS_LOCATIONS: Int = 2
const val USAGE_INTENT = "SERVICE_USED_BY"
fun convertLocation(l: Location?): net.osmand.Location? {
if (l == null) {
return null
}
val r = net.osmand.Location(l.provider)
r.latitude = l.latitude
r.longitude = l.longitude
r.time = l.time
if (l.hasAccuracy()) {
r.accuracy = l.accuracy
}
if (l.hasSpeed()) {
r.speed = l.speed
}
if (l.hasAltitude()) {
r.altitude = l.altitude
}
if (l.hasBearing()) {
r.bearing = l.bearing
}
if (l.hasAltitude()) {
r.altitude = l.altitude
}
return r
}
}
}

View file

@ -6,128 +6,128 @@ import net.osmand.telegram.utils.OsmandFormatter.SpeedConstants
class TelegramSettings(private val app: TelegramApplication) {
companion object {
companion object {
private const val SETTINGS_NAME = "osmand_telegram_settings"
private const val SETTINGS_NAME = "osmand_telegram_settings"
private const val SHARE_LOCATION_CHATS_KEY = "share_location_chats"
private const val SHOW_ON_MAP_CHATS_KEY = "show_on_map_chats"
private const val SHARE_LOCATION_CHATS_KEY = "share_location_chats"
private const val SHOW_ON_MAP_CHATS_KEY = "show_on_map_chats"
private const val METRICS_CONSTANTS_KEY = "metrics_constants"
private const val SPEED_CONSTANTS_KEY = "speed_constants"
private const val METRICS_CONSTANTS_KEY = "metrics_constants"
private const val SPEED_CONSTANTS_KEY = "speed_constants"
private const val SHOW_NOTIFICATION_ALWAYS_KEY = "show_notification_always"
}
private const val SHOW_NOTIFICATION_ALWAYS_KEY = "show_notification_always"
}
private var shareLocationChats: Set<String> = emptySet()
private var showOnMapChats: Set<String> = emptySet()
private var shareLocationChats: Set<String> = emptySet()
private var showOnMapChats: Set<String> = emptySet()
var metricsConstants = MetricsConstants.KILOMETERS_AND_METERS
var speedConstants = SpeedConstants.KILOMETERS_PER_HOUR
var metricsConstants = MetricsConstants.KILOMETERS_AND_METERS
var speedConstants = SpeedConstants.KILOMETERS_PER_HOUR
var showNotificationAlways = true
var showNotificationAlways = true
init {
read()
}
init {
read()
}
fun hasAnyChatToShareLocation(): Boolean {
return shareLocationChats.isNotEmpty()
}
fun hasAnyChatToShareLocation(): Boolean {
return shareLocationChats.isNotEmpty()
}
fun isSharingLocationToChat(chatTitle: String): Boolean {
return shareLocationChats.contains(chatTitle)
}
fun isSharingLocationToChat(chatTitle: String): Boolean {
return shareLocationChats.contains(chatTitle)
}
fun hasAnyChatToShowOnMap(): Boolean {
return showOnMapChats.isNotEmpty()
}
fun hasAnyChatToShowOnMap(): Boolean {
return showOnMapChats.isNotEmpty()
}
fun isShowingChatOnMap(chatTitle: String): Boolean {
return showOnMapChats.contains(chatTitle)
}
fun isShowingChatOnMap(chatTitle: String): Boolean {
return showOnMapChats.contains(chatTitle)
}
fun removeNonexistingChats(presentChatTitles: List<String>) {
val shareLocationChats = shareLocationChats.toMutableList()
shareLocationChats.intersect(presentChatTitles)
this.shareLocationChats = shareLocationChats.toHashSet()
fun removeNonexistingChats(presentChatTitles: List<String>) {
val shareLocationChats = shareLocationChats.toMutableList()
shareLocationChats.intersect(presentChatTitles)
this.shareLocationChats = shareLocationChats.toHashSet()
val showOnMapChats = showOnMapChats.toMutableList()
showOnMapChats.intersect(presentChatTitles)
this.showOnMapChats = showOnMapChats.toHashSet()
}
val showOnMapChats = showOnMapChats.toMutableList()
showOnMapChats.intersect(presentChatTitles)
this.showOnMapChats = showOnMapChats.toHashSet()
}
fun shareLocationToChat(chatTitle: String, share: Boolean) {
val shareLocationChats = shareLocationChats.toMutableList()
if (share) {
shareLocationChats.add(chatTitle)
} else {
shareLocationChats.remove(chatTitle)
}
this.shareLocationChats = shareLocationChats.toHashSet()
}
fun shareLocationToChat(chatTitle: String, share: Boolean) {
val shareLocationChats = shareLocationChats.toMutableList()
if (share) {
shareLocationChats.add(chatTitle)
} else {
shareLocationChats.remove(chatTitle)
}
this.shareLocationChats = shareLocationChats.toHashSet()
}
fun showChatOnMap(chatTitle: String, show: Boolean) {
val showOnMapChats = showOnMapChats.toMutableList()
if (show) {
showOnMapChats.add(chatTitle)
} else {
showOnMapChats.remove(chatTitle)
}
this.showOnMapChats = showOnMapChats.toHashSet()
}
fun showChatOnMap(chatTitle: String, show: Boolean) {
val showOnMapChats = showOnMapChats.toMutableList()
if (show) {
showOnMapChats.add(chatTitle)
} else {
showOnMapChats.remove(chatTitle)
}
this.showOnMapChats = showOnMapChats.toHashSet()
}
fun getShareLocationChats() = ArrayList(shareLocationChats)
fun getShowOnMapChats() = ArrayList(showOnMapChats)
fun getShareLocationChats() = ArrayList(shareLocationChats)
fun getShowOnMapChats() = ArrayList(showOnMapChats)
fun getShowOnMapChatsCount() = showOnMapChats.size
fun getShowOnMapChatsCount() = showOnMapChats.size
fun save() {
val prefs = app.getSharedPreferences(SETTINGS_NAME, Context.MODE_PRIVATE)
val edit = prefs.edit()
fun save() {
val prefs = app.getSharedPreferences(SETTINGS_NAME, Context.MODE_PRIVATE)
val edit = prefs.edit()
val shareLocationChatsSet = mutableSetOf<String>()
val shareLocationChats = ArrayList(shareLocationChats)
for (chatTitle in shareLocationChats) {
shareLocationChatsSet.add(chatTitle)
}
edit.putStringSet(SHARE_LOCATION_CHATS_KEY, shareLocationChatsSet)
val shareLocationChatsSet = mutableSetOf<String>()
val shareLocationChats = ArrayList(shareLocationChats)
for (chatTitle in shareLocationChats) {
shareLocationChatsSet.add(chatTitle)
}
edit.putStringSet(SHARE_LOCATION_CHATS_KEY, shareLocationChatsSet)
val showOnMapChatsSet = mutableSetOf<String>()
val showOnMapChats = ArrayList(showOnMapChats)
for (chatTitle in showOnMapChats) {
showOnMapChatsSet.add(chatTitle)
}
edit.putStringSet(SHOW_ON_MAP_CHATS_KEY, showOnMapChatsSet)
val showOnMapChatsSet = mutableSetOf<String>()
val showOnMapChats = ArrayList(showOnMapChats)
for (chatTitle in showOnMapChats) {
showOnMapChatsSet.add(chatTitle)
}
edit.putStringSet(SHOW_ON_MAP_CHATS_KEY, showOnMapChatsSet)
edit.putString(METRICS_CONSTANTS_KEY, metricsConstants.name)
edit.putString(SPEED_CONSTANTS_KEY, speedConstants.name)
edit.putString(METRICS_CONSTANTS_KEY, metricsConstants.name)
edit.putString(SPEED_CONSTANTS_KEY, speedConstants.name)
edit.putBoolean(SHOW_NOTIFICATION_ALWAYS_KEY, showNotificationAlways)
edit.putBoolean(SHOW_NOTIFICATION_ALWAYS_KEY, showNotificationAlways)
edit.apply()
}
edit.apply()
}
fun read() {
val prefs = app.getSharedPreferences(SETTINGS_NAME, Context.MODE_PRIVATE)
fun read() {
val prefs = app.getSharedPreferences(SETTINGS_NAME, Context.MODE_PRIVATE)
val shareLocationChats = mutableSetOf<String>()
val shareLocationChatsSet = prefs.getStringSet(SHARE_LOCATION_CHATS_KEY, mutableSetOf())
for (chatTitle in shareLocationChatsSet) {
shareLocationChats.add(chatTitle)
}
this.shareLocationChats = shareLocationChats
val shareLocationChats = mutableSetOf<String>()
val shareLocationChatsSet = prefs.getStringSet(SHARE_LOCATION_CHATS_KEY, mutableSetOf())
for (chatTitle in shareLocationChatsSet) {
shareLocationChats.add(chatTitle)
}
this.shareLocationChats = shareLocationChats
val showOnMapChats = mutableSetOf<String>()
val showOnMapChatsSet = prefs.getStringSet(SHOW_ON_MAP_CHATS_KEY, mutableSetOf())
for (chatTitle in showOnMapChatsSet) {
showOnMapChats.add(chatTitle)
}
this.showOnMapChats = showOnMapChats
val showOnMapChats = mutableSetOf<String>()
val showOnMapChatsSet = prefs.getStringSet(SHOW_ON_MAP_CHATS_KEY, mutableSetOf())
for (chatTitle in showOnMapChatsSet) {
showOnMapChats.add(chatTitle)
}
this.showOnMapChats = showOnMapChats
metricsConstants = MetricsConstants.valueOf(prefs.getString(METRICS_CONSTANTS_KEY, MetricsConstants.KILOMETERS_AND_METERS.name))
speedConstants = SpeedConstants.valueOf(prefs.getString(SPEED_CONSTANTS_KEY, SpeedConstants.KILOMETERS_PER_HOUR.name))
metricsConstants = MetricsConstants.valueOf(prefs.getString(METRICS_CONSTANTS_KEY, MetricsConstants.KILOMETERS_AND_METERS.name))
speedConstants = SpeedConstants.valueOf(prefs.getString(SPEED_CONSTANTS_KEY, SpeedConstants.KILOMETERS_PER_HOUR.name))
showNotificationAlways = prefs.getBoolean(SHOW_NOTIFICATION_ALWAYS_KEY, true)
}
showNotificationAlways = prefs.getBoolean(SHOW_NOTIFICATION_ALWAYS_KEY, true)
}
}

View file

@ -6,88 +6,88 @@ import net.osmand.telegram.notifications.TelegramNotification.NotificationType
class ShareLocationHelper(private val app: TelegramApplication) {
companion object {
const val MAX_LOCATION_MESSAGE_LIVE_PERIOD_SEC = 60 * 60 * 24 - 1 // day
}
companion object {
const val MAX_LOCATION_MESSAGE_LIVE_PERIOD_SEC = 60 * 60 * 24 - 1 // day
}
var sharingLocation: Boolean = false
private set
var sharingLocation: Boolean = false
private set
var duration: Long = 0
private set
var duration: Long = 0
private set
var distance: Int = 0
private set
var distance: Int = 0
private set
var lastLocationMessageSentTime: Long = 0
var lastLocationMessageSentTime: Long = 0
private var lastTimeInMillis: Long = 0L
private var lastTimeInMillis: Long = 0L
private var lastLocation: Location? = null
set(value) {
if (lastTimeInMillis == 0L) {
lastTimeInMillis = System.currentTimeMillis()
} else {
val currentTimeInMillis = System.currentTimeMillis()
duration += currentTimeInMillis - lastTimeInMillis
lastTimeInMillis = currentTimeInMillis
}
if (lastLocation != null && value != null) {
distance += value.distanceTo(lastLocation).toInt()
}
field = value
}
private var lastLocation: Location? = null
set(value) {
if (lastTimeInMillis == 0L) {
lastTimeInMillis = System.currentTimeMillis()
} else {
val currentTimeInMillis = System.currentTimeMillis()
duration += currentTimeInMillis - lastTimeInMillis
lastTimeInMillis = currentTimeInMillis
}
if (lastLocation != null && value != null) {
distance += value.distanceTo(lastLocation).toInt()
}
field = value
}
fun updateLocation(location: Location?) {
lastLocation = location
fun updateLocation(location: Location?) {
lastLocation = location
if (location != null && app.isInternetConnectionAvailable) {
val shareLocationChats = app.settings.getShareLocationChats()
if (shareLocationChats.isNotEmpty()) {
app.telegramHelper.sendLiveLocationMessage(shareLocationChats, MAX_LOCATION_MESSAGE_LIVE_PERIOD_SEC, location.latitude, location.longitude)
}
lastLocationMessageSentTime = System.currentTimeMillis()
}
refreshNotification()
}
if (location != null && app.isInternetConnectionAvailable) {
val shareLocationChats = app.settings.getShareLocationChats()
if (shareLocationChats.isNotEmpty()) {
app.telegramHelper.sendLiveLocationMessage(shareLocationChats, MAX_LOCATION_MESSAGE_LIVE_PERIOD_SEC, location.latitude, location.longitude)
}
lastLocationMessageSentTime = System.currentTimeMillis()
}
refreshNotification()
}
fun startSharingLocation() {
if (!sharingLocation) {
sharingLocation = true
fun startSharingLocation() {
if (!sharingLocation) {
sharingLocation = true
app.startMyLocationService()
app.startMyLocationService()
refreshNotification()
}
}
refreshNotification()
}
}
fun stopSharingLocation() {
if (sharingLocation) {
sharingLocation = false
fun stopSharingLocation() {
if (sharingLocation) {
sharingLocation = false
app.stopMyLocationService()
lastLocation = null
lastTimeInMillis = 0L
distance = 0
duration = 0
app.stopMyLocationService()
lastLocation = null
lastTimeInMillis = 0L
distance = 0
duration = 0
refreshNotification()
}
}
refreshNotification()
}
}
fun pauseSharingLocation() {
sharingLocation = false
fun pauseSharingLocation() {
sharingLocation = false
app.stopMyLocationService()
lastLocation = null
lastTimeInMillis = 0L
app.stopMyLocationService()
lastLocation = null
lastTimeInMillis = 0L
refreshNotification()
}
refreshNotification()
}
private fun refreshNotification() {
app.runInUIThread {
app.notificationHelper.refreshNotification(NotificationType.SHARE_LOCATION)
}
}
private fun refreshNotification() {
app.runInUIThread {
app.notificationHelper.refreshNotification(NotificationType.LOCATION)
}
}
}

View file

@ -7,77 +7,77 @@ import org.drinkless.td.libcore.telegram.TdApi
class ShowLocationHelper(private val app: TelegramApplication) {
companion object {
private const val MAP_LAYER_ID = "telegram_layer"
}
companion object {
private const val MAP_LAYER_ID = "telegram_layer"
}
private val telegramHelper = app.telegramHelper
private val osmandHelper = app.osmandHelper
private val telegramHelper = app.telegramHelper
private val osmandHelper = app.osmandHelper
var showingLocation: Boolean = false
private set
var showingLocation: Boolean = false
private set
private fun setMapLayer() {
osmandHelper.addMapLayer(MAP_LAYER_ID, "Telegram", 5.5f, null)
}
private fun setMapLayer() {
osmandHelper.addMapLayer(MAP_LAYER_ID, "Telegram", 5.5f, null)
}
fun showLocationOnMap(chatTitle: String, message: TdApi.Message) {
if (osmandHelper.isOsmandConnected()) {
val content = message.content
if (content is TdApi.MessageLocation) {
var userName = ""
val user = telegramHelper.getUser(message.senderUserId)
if (user != null) {
userName = "${user.firstName} ${user.lastName}".trim()
if (userName.isEmpty()) {
userName = user.username
}
if (userName.isEmpty()) {
userName = user.phoneNumber
}
}
if (userName.isEmpty()) {
userName = message.senderUserId.toString()
}
setMapLayer()
osmandHelper.addMapPoint(MAP_LAYER_ID, "${chatTitle}_${message.senderUserId}", userName, userName,
chatTitle, Color.RED, ALatLon(content.location.latitude, content.location.longitude), null)
}
}
}
fun showLocationOnMap(chatTitle: String, message: TdApi.Message) {
if (osmandHelper.isOsmandConnected()) {
val content = message.content
if (content is TdApi.MessageLocation) {
var userName = ""
val user = telegramHelper.getUser(message.senderUserId)
if (user != null) {
userName = "${user.firstName} ${user.lastName}".trim()
if (userName.isEmpty()) {
userName = user.username
}
if (userName.isEmpty()) {
userName = user.phoneNumber
}
}
if (userName.isEmpty()) {
userName = message.senderUserId.toString()
}
setMapLayer()
osmandHelper.addMapPoint(MAP_LAYER_ID, "${chatTitle}_${message.senderUserId}", userName, userName,
chatTitle, Color.RED, ALatLon(content.location.latitude, content.location.longitude), null)
}
}
}
fun showChatMessages(chatTitle: String) {
if (osmandHelper.isOsmandConnected()) {
val messages = telegramHelper.getChatMessages(chatTitle)
for (message in messages) {
showLocationOnMap(chatTitle, message)
}
}
}
fun showChatMessages(chatTitle: String) {
if (osmandHelper.isOsmandConnected()) {
val messages = telegramHelper.getChatMessages(chatTitle)
for (message in messages) {
showLocationOnMap(chatTitle, message)
}
}
}
fun hideChatMessages(chatTitle: String) {
if (osmandHelper.isOsmandConnected()) {
val messages = telegramHelper.getChatMessages(chatTitle)
for (message in messages) {
val user = telegramHelper.getUser(message.senderUserId)
if (user != null) {
osmandHelper.removeMapPoint(MAP_LAYER_ID, "${chatTitle}_${message.senderUserId}")
}
}
}
}
fun hideChatMessages(chatTitle: String) {
if (osmandHelper.isOsmandConnected()) {
val messages = telegramHelper.getChatMessages(chatTitle)
for (message in messages) {
val user = telegramHelper.getUser(message.senderUserId)
if (user != null) {
osmandHelper.removeMapPoint(MAP_LAYER_ID, "${chatTitle}_${message.senderUserId}")
}
}
}
}
fun startShowingLocation() {
if (!showingLocation) {
showingLocation = true
app.startUserLocationService()
}
}
fun startShowingLocation() {
if (!showingLocation) {
showingLocation = true
app.startUserLocationService()
}
}
fun stopShowingLocation() {
if (showingLocation) {
showingLocation = false
app.stopUserLocationService()
}
}
fun stopShowingLocation() {
if (showingLocation) {
showingLocation = false
app.stopUserLocationService()
}
}
}

View file

@ -0,0 +1,60 @@
package net.osmand.telegram.notifications
import android.support.v4.app.NotificationCompat
import android.support.v4.content.ContextCompat
import net.osmand.telegram.R
import net.osmand.telegram.TelegramApplication
import net.osmand.telegram.utils.OsmandFormatter
import net.osmand.util.Algorithms
class LocationNotification(app: TelegramApplication) : TelegramNotification(app, GROUP_NAME) {
companion object {
const val GROUP_NAME = "share_location"
}
override val type: TelegramNotification.NotificationType
get() = TelegramNotification.NotificationType.LOCATION
override val priority: Int
get() = NotificationCompat.PRIORITY_DEFAULT
override val isActive: Boolean
get() {
val service = app.telegramService
return isEnabled && service != null
}
override val isEnabled: Boolean
get() = app.settings.hasAnyChatToShareLocation()
override val telegramNotificationId: Int
get() = TelegramNotification.LOCATION_NOTIFICATION_SERVICE_ID
override val telegramWearableNotificationId: Int
get() = TelegramNotification.WEAR_LOCATION_NOTIFICATION_SERVICE_ID
override fun buildNotification(wearable: Boolean): NotificationCompat.Builder {
val notificationTitle: String
val notificationText: String
val shareLocationHelper = app.shareLocationHelper
if (shareLocationHelper.sharingLocation) {
val sharedDistance = shareLocationHelper.distance.toFloat()
color = ContextCompat.getColor(app, R.color.osmand_orange)
icon = R.drawable.ic_action_polygom_dark
notificationTitle = (app.getString(R.string.sharing_location) + ""
+ Algorithms.formatDuration((shareLocationHelper.duration / 1000).toInt(), true))
notificationText = (app.getString(R.string.shared_string_distance)
+ ": " + OsmandFormatter.getFormattedDistance(sharedDistance, app))
} else {
notificationTitle = app.getString(R.string.show_users_on_map)
notificationText = app.getString(R.string.active_chats) + ": " + app.settings.getShowOnMapChatsCount()
color = 0
icon = R.drawable.ic_action_view
}
return createBuilder(wearable)
.setContentTitle(notificationTitle)
.setStyle(NotificationCompat.BigTextStyle().bigText(notificationText))
}
}

View file

@ -5,46 +5,43 @@ import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
import android.support.v4.app.NotificationManagerCompat
import net.osmand.telegram.R
import net.osmand.telegram.TelegramApplication
import net.osmand.telegram.notifications.TelegramNotification.NotificationType
import java.util.*
class NotificationHelper(private val app: TelegramApplication) {
val shareLocationNotification = ShareLocationNotification(app)
val showLocationNotification = ShowLocationNotification(app)
val locationNotification = LocationNotification(app)
private val all = listOf(shareLocationNotification, showLocationNotification)
private val all = listOf(locationNotification)
fun buildNotification(telegramNotification: TelegramNotification): Notification {
return telegramNotification.buildNotification(false).build()
}
fun buildNotification(telegramNotification: TelegramNotification): Notification {
return telegramNotification.buildNotification(false).build()
}
fun refreshNotification(notificationType: NotificationType) {
for (notification in all) {
if (notification.type == notificationType) {
notification.refreshNotification()
break
}
}
}
fun refreshNotification(notificationType: NotificationType) {
for (notification in all) {
if (notification.type == notificationType) {
notification.refreshNotification()
break
}
}
}
@TargetApi(26)
fun createNotificationChannel() {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
val channel = NotificationChannel(NOTIFICATION_CHANEL_ID,
app.getString(R.string.osmand_service), NotificationManager.IMPORTANCE_LOW)
channel.enableVibration(false)
channel.description = app.getString(R.string.osmand_service_descr)
val mNotificationManager = app
.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
mNotificationManager.createNotificationChannel(channel)
}
}
@TargetApi(26)
fun createNotificationChannel() {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
val channel = NotificationChannel(NOTIFICATION_CHANEL_ID,
app.getString(R.string.osmand_service), NotificationManager.IMPORTANCE_LOW)
channel.enableVibration(false)
channel.description = app.getString(R.string.osmand_service_descr)
val mNotificationManager = app
.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
mNotificationManager.createNotificationChannel(channel)
}
}
companion object {
const val NOTIFICATION_CHANEL_ID = "osmand_telegram_background_service"
}
companion object {
const val NOTIFICATION_CHANEL_ID = "osmand_telegram_background_service"
}
}

View file

@ -1,51 +0,0 @@
package net.osmand.telegram.notifications
import android.support.v4.app.NotificationCompat
import android.support.v4.content.ContextCompat
import net.osmand.telegram.R
import net.osmand.telegram.TelegramApplication
import net.osmand.telegram.utils.OsmandFormatter
import net.osmand.util.Algorithms
class ShareLocationNotification(app: TelegramApplication) : TelegramNotification(app, GROUP_NAME) {
companion object {
const val GROUP_NAME = "share_location"
}
override val type: TelegramNotification.NotificationType
get() = TelegramNotification.NotificationType.SHARE_LOCATION
override val priority: Int
get() = NotificationCompat.PRIORITY_DEFAULT
override val isActive: Boolean
get() {
val service = app.myLocationService
return isEnabled && service != null
}
override val isEnabled: Boolean
get() = app.settings.hasAnyChatToShareLocation()
override val telegramNotificationId: Int
get() = TelegramNotification.SHARE_LOCATION_NOTIFICATION_SERVICE_ID
override val telegramWearableNotificationId: Int
get() = TelegramNotification.WEAR_SHARE_LOCATION_NOTIFICATION_SERVICE_ID
override fun buildNotification(wearable: Boolean): NotificationCompat.Builder {
icon = R.drawable.ic_action_polygom_dark
val shareLocationHelper = app.shareLocationHelper
val sharedDistance = shareLocationHelper.distance.toFloat()
color = ContextCompat.getColor(app, R.color.osmand_orange)
val notificationTitle = (app.getString(R.string.sharing_location) + ""
+ Algorithms.formatDuration((shareLocationHelper.duration / 1000).toInt(), true))
val notificationText = (app.getString(R.string.shared_string_distance)
+ ": " + OsmandFormatter.getFormattedDistance(sharedDistance, app))
return createBuilder(wearable)
.setContentTitle(notificationTitle)
.setStyle(NotificationCompat.BigTextStyle().bigText(notificationText))
}
}

View file

@ -1,45 +0,0 @@
package net.osmand.telegram.notifications
import android.support.v4.app.NotificationCompat
import net.osmand.telegram.R
import net.osmand.telegram.TelegramApplication
class ShowLocationNotification(app: TelegramApplication) : TelegramNotification(app, GROUP_NAME) {
companion object {
const val GROUP_NAME = "show_location"
}
override val type: TelegramNotification.NotificationType
get() = NotificationType.SHOW_LOCATION
override val priority: Int
get() = NotificationCompat.PRIORITY_DEFAULT
override val isActive: Boolean
get() {
val service = app.userLocationService
return isEnabled && service != null
}
override val isEnabled: Boolean
get() = app.settings.hasAnyChatToShowOnMap()
override val telegramNotificationId: Int
get() = TelegramNotification.SHOW_LOCATION_NOTIFICATION_SERVICE_ID
override val telegramWearableNotificationId: Int
get() = TelegramNotification.WEAR_SHOW_LOCATION_NOTIFICATION_SERVICE_ID
override fun buildNotification(wearable: Boolean): NotificationCompat.Builder {
val notificationTitle: String = app.getString(R.string.show_users_on_map)
val notificationText: String = app.getString(R.string.active_chats) + ": " + app.settings.getShowOnMapChatsCount()
color = 0
icon = R.drawable.ic_action_view
return createBuilder(wearable)
.setContentTitle(notificationTitle)
.setStyle(NotificationCompat.BigTextStyle().bigText(notificationText))
}
}

View file

@ -13,11 +13,9 @@ abstract class TelegramNotification(protected var app: TelegramApplication, val
companion object {
const val SHARE_LOCATION_NOTIFICATION_SERVICE_ID = 6
const val SHOW_LOCATION_NOTIFICATION_SERVICE_ID = 7
const val LOCATION_NOTIFICATION_SERVICE_ID = 6
const val WEAR_SHARE_LOCATION_NOTIFICATION_SERVICE_ID = 1006
const val WEAR_SHOW_LOCATION_NOTIFICATION_SERVICE_ID = 1006
const val WEAR_LOCATION_NOTIFICATION_SERVICE_ID = 1006
}
protected var ongoing = true
@ -37,8 +35,7 @@ abstract class TelegramNotification(protected var app: TelegramApplication, val
abstract val isEnabled: Boolean
enum class NotificationType {
SHARE_LOCATION,
SHOW_LOCATION
LOCATION,
}
@SuppressLint("InlinedApi")

View file

@ -1,133 +0,0 @@
package net.osmand.telegram.services
import android.app.Service
import android.content.Context
import android.content.Intent
import android.location.Location
import android.location.LocationListener
import android.location.LocationManager
import android.os.Binder
import android.os.Bundle
import android.os.Handler
import android.os.IBinder
import android.util.Log
import android.widget.Toast
import net.osmand.PlatformUtil
import net.osmand.telegram.R
import net.osmand.telegram.TelegramApplication
class MyLocationService : Service(), LocationListener {
private val binder = LocationServiceBinder()
private fun app() = application as TelegramApplication
var handler: Handler? = null
class LocationServiceBinder : Binder()
override fun onBind(intent: Intent): IBinder? {
return binder
}
fun stopIfNeeded(ctx: Context) {
val serviceIntent = Intent(ctx, MyLocationService::class.java)
ctx.stopService(serviceIntent)
}
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
handler = Handler()
val app = app()
app.myLocationService = this
// requesting
// request location updates
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
try {
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0f, this@MyLocationService)
} catch (e: SecurityException) {
Toast.makeText(this, R.string.no_location_permission, Toast.LENGTH_LONG).show()
Log.d(PlatformUtil.TAG, "Location service permission not granted")
} catch (e: IllegalArgumentException) {
Toast.makeText(this, R.string.gps_not_available, Toast.LENGTH_LONG).show()
Log.d(PlatformUtil.TAG, "GPS location provider not available")
}
val shareLocationNotification = app.notificationHelper.shareLocationNotification
val notification = app.notificationHelper.buildNotification(shareLocationNotification)
startForeground(shareLocationNotification.telegramNotificationId, notification)
app.notificationHelper.refreshNotification(shareLocationNotification.type)
return Service.START_REDELIVER_INTENT
}
override fun onDestroy() {
super.onDestroy()
val app = app()
app.myLocationService = null
// remove updates
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
try {
locationManager.removeUpdates(this)
} catch (e: SecurityException) {
Log.d(PlatformUtil.TAG, "Location service permission not granted")
}
// remove notification
stopForeground(java.lang.Boolean.TRUE)
}
override fun onLocationChanged(l: Location?) {
if (l != null) {
val location = convertLocation(l)
app().shareLocationHelper.updateLocation(location)
}
}
override fun onProviderDisabled(provider: String) {
Toast.makeText(this, getString(R.string.location_service_no_gps_available), Toast.LENGTH_LONG).show()
}
override fun onProviderEnabled(provider: String) {}
override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {}
override fun onTaskRemoved(rootIntent: Intent) {
val app = app()
if (app.myLocationService != null) {
// Do not stop service after UI task was dismissed
//this@MyLocationService.stopSelf()
}
}
companion object {
fun convertLocation(l: Location?): net.osmand.Location? {
if (l == null) {
return null
}
val r = net.osmand.Location(l.provider)
r.latitude = l.latitude
r.longitude = l.longitude
r.time = l.time
if (l.hasAccuracy()) {
r.accuracy = l.accuracy
}
if (l.hasSpeed()) {
r.speed = l.speed
}
if (l.hasAltitude()) {
r.altitude = l.altitude
}
if (l.hasBearing()) {
r.bearing = l.bearing
}
if (l.hasAltitude()) {
r.altitude = l.altitude
}
return r
}
}
}

View file

@ -1,81 +0,0 @@
package net.osmand.telegram.services
import android.app.Service
import android.content.Context
import android.content.Intent
import android.os.AsyncTask
import android.os.Binder
import android.os.Handler
import android.os.IBinder
import net.osmand.telegram.TelegramApplication
import net.osmand.telegram.helpers.TelegramHelper.TelegramIncomingMessagesListener
import org.drinkless.td.libcore.telegram.TdApi
import java.util.concurrent.Executors
class UserLocationService : Service(), TelegramIncomingMessagesListener {
private val binder = LocationServiceBinder()
private fun app() = application as TelegramApplication
private val executor = Executors.newSingleThreadExecutor()
var handler: Handler? = null
class LocationServiceBinder : Binder()
override fun onBind(intent: Intent): IBinder? {
return binder
}
override fun onReceiveChatLocationMessages(chatTitle: String, vararg messages: TdApi.Message) {
val app = app()
if (app.settings.isShowingChatOnMap(chatTitle)) {
ShowMessagesTask(app, chatTitle).executeOnExecutor(executor, *messages)
}
}
fun stopIfNeeded(ctx: Context) {
val serviceIntent = Intent(ctx, UserLocationService::class.java)
ctx.stopService(serviceIntent)
}
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
handler = Handler()
val app = app()
app.userLocationService = this
app.telegramHelper.incomingMessagesListener = this
val showLocationNotification = app.notificationHelper.showLocationNotification
val notification = app.notificationHelper.buildNotification(showLocationNotification)
startForeground(showLocationNotification.telegramNotificationId, notification)
app.notificationHelper.refreshNotification(showLocationNotification.type)
return Service.START_REDELIVER_INTENT
}
override fun onDestroy() {
super.onDestroy()
val app = app()
app.telegramHelper.incomingMessagesListener = null
app.userLocationService = null
stopForeground(java.lang.Boolean.TRUE)
}
override fun onTaskRemoved(rootIntent: Intent) {
val app = app()
if (app.userLocationService != null) {
// Do not stop service after UI task was dismissed
//this@MyLocationService.stopSelf()
}
}
class ShowMessagesTask(private val app: TelegramApplication, private val chatTitle: String) : AsyncTask<TdApi.Message, Void, Void?>() {
override fun doInBackground(vararg messages: TdApi.Message): Void? {
for (message in messages) {
app.showLocationHelper.showLocationOnMap(chatTitle, message)
}
return null
}
}
}

View file

@ -819,7 +819,10 @@ public class OsmandAidlApi {
boolean updateMapLayer(AMapLayer layer) {
if (layer != null && layers.containsKey(layer.getId())) {
layers.put(layer.getId(), layer);
AMapLayer existingLayer = layers.get(layer.getId());
for (AMapPoint point : layer.getPoints()) {
existingLayer.putPoint(point);
}
refreshMap();
return true;
} else {