I have recently tried to use ExoPlayer from google in my android project. Exoplayer is keep playing video even I have call all the necessary stuff & player is not being released.It appear releasePlayer() doesn't works at all. Video keep playing even if i move to other activity. I have tried all the solutions available on stack or codelabs sites etc. Which makes me to put this question here on stack.
package com.android.maccino.ui
import android.content.Intent
import android.media.MediaPlayer
import android.net.Uri
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import com.android.maccino.R
import com.android.maccino.models.SponsorModel
import com.android.maccino.utils.AppConstants
import com.android.maccino.utils.AppUtils
import com.google.android.exoplayer2.*
import com.google.android.exoplayer2.source.ExtractorMediaSource
import com.google.android.exoplayer2.source.MediaSource
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.*
import com.kaopiz.kprogresshud.KProgressHUD
import com.orhanobut.logger.Logger
import com.squareup.picasso.Picasso
import kotlinx.android.synthetic.main.activity_dashboard.*
import java.util.*
class DashboardActivity : AppCompatActivity() {
lateinit var sponsorModel: SponsorModel
lateinit var mDatabaseRef: DatabaseReference
lateinit var kProgressHud: KProgressHUD
lateinit var mSponsorList: MutableList<SponsorModel>
lateinit var player: SimpleExoPlayer
var currentWindow: Int = 0
var playbackPosition: Long = 0;
var wasPlayingBefore: Boolean = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_dashboard)
mDatabaseRef = FirebaseDatabase.getInstance().reference
sponsorModel = SponsorModel()
mSponsorList = ArrayList<SponsorModel>()
Logger.d(FirebaseAuth.getInstance().currentUser!!.uid)
if (intent != null &&
intent.getSerializableExtra(AppConstants.INTENT_SPONSOR_MODEL) != null) {
sponsorModel = intent.getSerializableExtra(AppConstants.INTENT_SPONSOR_MODEL) as SponsorModel
setValues()
}
btnAnswer1.setOnClickListener {
if (sponsorModel.answers.get(0).getValue(btnAnswer1.text.toString()) == true) {
makeAnsweredSponsorEntry()
startActivity(Intent(this#DashboardActivity, CorrectAnswer::class.java).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP).putExtra(AppConstants.INTENT_SPONSOR_MODEL, sponsorModel))
this.finish()
} else if (sponsorModel.answers.get(0).getValue(btnAnswer1.text.toString()) == false) {
startActivity(Intent(this#DashboardActivity, WrongAnswer::class.java))
}
}
btnAnswer2.setOnClickListener {
if (sponsorModel.answers.get(1).getValue(btnAnswer2.text.toString()) == true) {
makeAnsweredSponsorEntry()
startActivity(Intent(this#DashboardActivity, CorrectAnswer::class.java).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP).putExtra(AppConstants.INTENT_SPONSOR_MODEL, sponsorModel))
this.finish()
} else if (sponsorModel.answers.get(1).getValue(btnAnswer2.text.toString()) == false) {
startActivity(Intent(this#DashboardActivity, WrongAnswer::class.java))
}
}
btnAnswer3.setOnClickListener {
if (sponsorModel.answers.get(2).getValue(btnAnswer3.text.toString()) == true) {
makeAnsweredSponsorEntry()
startActivity(Intent(this#DashboardActivity, CorrectAnswer::class.java).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP).putExtra(AppConstants.INTENT_SPONSOR_MODEL, sponsorModel))
this.finish()
} else if (sponsorModel.answers.get(2).getValue(btnAnswer3.text.toString()) == false) {
startActivity(Intent(this#DashboardActivity, WrongAnswer::class.java))
}
}
tvSearch.setOnClickListener { startActivity(Intent(this#DashboardActivity, SearchActivity::class.java).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)) }
}
override fun onResume() {
super.onResume()
initializePlayer()
}
override fun onPause() {
super.onPause()
if (Util.SDK_INT <= 23) {
releasePlayer();
}
}
private fun setValues() {
try {
tvQuestion.setText(sponsorModel.question)
sponsorModel.answers.get(0).keys.forEach { key: String ->
btnAnswer1.setText(key)
}
sponsorModel.answers.get(1).keys.forEach { key: String ->
btnAnswer2.setText(key)
}
sponsorModel.answers.get(2).keys.forEach { key: String ->
btnAnswer3.setText(key)
}
tvSponsorName.setText(sponsorModel.sponsor_name)
Picasso.with(this#DashboardActivity).load(sponsorModel.logo).into(ivSponsorLogo)
ivFlag.setOnClickListener { startActivity(Intent(Intent.ACTION_VIEW).setDataAndType(Uri.parse(sponsorModel.video_url), "video/*")) }
initializePlayer()
} catch (e: Exception) {
e.printStackTrace()
}
}
//Player implementation
private fun initializePlayer() {
try {
player = ExoPlayerFactory.newSimpleInstance(
DefaultRenderersFactory(this#DashboardActivity),
DefaultTrackSelector(), DefaultLoadControl())
player.repeatMode = Player.REPEAT_MODE_ALL
playerView.player = player
playerView.hideController()
player.setPlayWhenReady(true)
player.seekTo(currentWindow, playbackPosition);
val uri = Uri.parse(sponsorModel.video_url)
val mediaSource = buildMediaSource(uri)
player.prepare(mediaSource, true, false)
wasPlayingBefore = true
} catch (e: Exception) {
e.printStackTrace()
}
}
private fun buildMediaSource(uri: Uri): MediaSource {
return ExtractorMediaSource.Factory(
DefaultHttpDataSourceFactory("exoplayer-maccino")).createMediaSource(uri)
}
private fun releasePlayer() {
if (player != null) {
playbackPosition = player.currentPosition
currentWindow = player.currentWindowIndex
player.playWhenReady = false
player.setRepeatMode(Player.REPEAT_MODE_OFF)
player.stop()
player.release()
playerView.player = null
// player = null
}
}
}
Related
I want to show a custom view when the app is turned off or when the app is turned on, depending on the phone state.
so I use WindowManager. but get error message
W/System.err: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?
W/System.err: at android.view.ViewRootImpl.setView(ViewRootImpl.java:1596)
W/System.err: at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:509)
W/System.err: at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:133)
W/System.err: at com.reactnativecallerid.service.CallerIdOverlay.showRingingView(CallerIdOverlay.kt:190)
W/System.err: at com.reactnativecallerid.service.CallerIDService$procIncomingCallRinging$1.onSuccess(CallerIDService.kt:177)
W/System.err: at com.reactnativecallerid.service.CallerIDService$Companion.addEventListener(CallerIDService.kt:520)
W/System.err: at com.reactnativecallerid.CallerIdModule.addEventListener(CallerIdModule.kt:34)
W/System.err: at java.lang.reflect.Method.invoke(Native Method)
W/System.err: at com.facebook.react.bridge.JavaMethodWrapper.invoke(JavaMethodWrapper.java:372)
W/System.err: at com.facebook.react.bridge.JavaModuleWrapper.invoke(JavaModuleWrapper.java:188)
W/System.err: at com.facebook.react.bridge.queue.NativeRunnable.run(Native Method)
W/System.err: at android.os.Handler.handleCallback(Handler.java:938)
W/System.err: at android.os.Handler.dispatchMessage(Handler.java:99)
W/System.err: at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:27)
W/System.err: at android.os.Looper.loopOnce(Looper.java:226)
W/System.err: at android.os.Looper.loop(Looper.java:313)
CallerIdOverlay.kt
package com.reactnativecallerid.service
import android.content.Context
import android.graphics.Bitmap
import android.graphics.PixelFormat
import android.os.Build
import android.util.Log
import android.view.*
import android.view.View.OnTouchListener
import android.widget.ImageView
import android.widget.TextView
import com.bumptech.glide.Glide
import com.bumptech.glide.request.target.BitmapImageViewTarget
import com.facebook.react.BuildConfig
import com.reactnativecallerid.R
import com.reactnativecallerid.model.EstimationStatusCode
import com.reactnativecallerid.model.EstimationStatusCode.getStatus
class CallerIdOverlay(context: CallerIDService) {
var mWindowManager: WindowManager? = null
var service: CallerIDService = context
private var mInflater: LayoutInflater? = null
var mRootView: View? = null
var mContentView: ViewGroup? = null
var mLayoutParams: WindowManager.LayoutParams? = null
var mLayoutRinging: View? = null
var mViewType: CallerIDService.ViewType = CallerIDService.ViewType.NONE
var isShown = false
private set
fun onCreate() {
mWindowManager = service.getSystemService(Context.WINDOW_SERVICE) as WindowManager?
mInflater = LayoutInflater.from(service)
mInflater?.let { _mInflater -> mRootView = _mInflater.inflate(R.layout.callerid, null) }
mContentView = mRootView!!.findViewById<View>(R.id.content) as ViewGroup
mInflater?.let { _mInflater -> mLayoutRinging = _mInflater.inflate(R.layout.callerid_ringing, mContentView, false) }
mLayoutRinging!!.findViewById<View>(R.id.close).setOnClickListener { hideView() }
false) }
mLayoutIdle!!.findViewById<View>(R.id.close).setOnClickListener { hideView() }
val layoutFlag: Int = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
WindowManager.LayoutParams.TYPE_APPLICATION_PANEL
} else {
WindowManager.LayoutParams.TYPE_PHONE
}
mLayoutParams = WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.WRAP_CONTENT,
layoutFlag,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
PixelFormat.TRANSLUCENT
)
mLayoutParams!!.gravity = Gravity.TOP or Gravity.LEFT
mLayoutParams!!.x = 0
mLayoutParams!!.y = 0
mRootView!!.setOnTouchListener(object : OnTouchListener {
private var initialY = 0
private var initialTouchY = 0f
private var sentGAEvent = false
override fun onTouch(v: View, event: MotionEvent): Boolean {
when (event.action) {
MotionEvent.ACTION_DOWN -> {
initialY = mLayoutParams!!.y
initialTouchY = event.rawY
if (mViewType === CallerIDService.ViewType.RINGING) {
mLayoutRinging!!.findViewById<View>(R.id.layout_card)
.setBackgroundResource(R.drawable.bg_box_cid_over)
mLayoutRinging!!.findViewById<View>(R.id.image).alpha = 0.8f
} else if (mViewType === CallerIDService.ViewType.CONNECTED) {
mLayoutConnected!!.findViewById<View>(R.id.layout_card)
.setBackgroundResource(R.drawable.bg_box_cid_over)
} else if (mViewType === CallerIDService.ViewType.IDLE) {
mLayoutIdle!!.findViewById<View>(R.id.layout_card)
.setBackgroundResource(R.drawable.bg_box_cid_over)
}
sentGAEvent = false
return true
}
MotionEvent.ACTION_UP -> {
if (mViewType === CallerIDService.ViewType.RINGING) {
mLayoutRinging!!.findViewById<View>(R.id.layout_card)
.setBackgroundResource(R.drawable.bg_box_cid)
mLayoutRinging!!.findViewById<View>(R.id.image).alpha = 1.0f
} else if (mViewType === CallerIDService.ViewType.CONNECTED) {
mLayoutConnected!!.findViewById<View>(R.id.layout_card)
.setBackgroundResource(R.drawable.bg_box_cid)
} else if (mViewType === CallerIDService.ViewType.IDLE) {
mLayoutIdle!!.findViewById<View>(R.id.layout_card)
.setBackgroundResource(R.drawable.bg_box_cid)
}
sentGAEvent = false
return true
}
MotionEvent.ACTION_MOVE -> {
mLayoutParams!!.y = initialY + (event.rawY - initialTouchY).toInt()
try {
mWindowManager!!.updateViewLayout(mRootView, mLayoutParams)
} catch (ignore: Exception) {
}
return true
}
}
return false
}
})
}
fun onDestory() {
try {
isShown = false
if (mWindowManager != null && mRootView != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (mRootView!!.isAttachedToWindow) {
mWindowManager!!.removeView(mRootView)
}
} else {
mWindowManager!!.removeView(mRootView)
}
}
} catch (e: Exception) {
e.printStackTrace()
} finally {
service.stopForeground(true)
}
}
fun showRingingView(userinfo: ICallerIdViewItem, phoneNumber: String?) {
try {
isShown = true
//imgurls
if (userinfo.imgurls != null && userinfo.imgurls!!.size > 0) {
Glide.with(service).asBitmap().load(userinfo.imgurls!![0]!!.thumb_w456).into(
BitmapImageViewTarget(mLayoutRinging!!.findViewById<View>(R.id.image) as ImageView)
)
}
//statuscode
if (userinfo.statuscode != null && userinfo.statuscodeName != null) {
(mLayoutRinging!!.findViewById<View>(R.id.statusname) as TextView).text =
userinfo.statuscodeName
}
// phonenumber
(mLayoutRinging!!.findViewById<View>(R.id.phonenumber) as TextView).text = phoneNumber
mContentView!!.removeAllViews()
mContentView!!.addView(mLayoutRinging)
mRootView!!.visibility = View.VISIBLE
mViewType = CallerIDService.ViewType.RINGING
if (mRootView!!.parent != null) {
mWindowManager!!.removeView(mRootView)
}
mWindowManager!!.addView(mRootView, mLayoutParams)
} catch (e: Exception) {
e.printStackTrace()
}
}
fun hideView() {
try {
isShown = false
if (BuildConfig.DEBUG) Log.d("CallerIdOverlay", "hideView()")
service.stop()
mRootView!!.visibility = View.GONE
mViewType = CallerIDService.ViewType.NONE
if (mRootView!!.parent != null) {
mWindowManager!!.removeView(mRootView)
}
} catch (e: Exception) {
e.printStackTrace()
}
}
interface ICallerIdViewItem {
val phonenumber: String?
val statuscode: String?
val imgurls: List<IImgurlViewItem?>?
companion object {
const val TYPE_REPAIR_SHOP = "shop"
const val TYPE_TECH_SHOP = "techshop"
}
}
interface IImgurlViewItem {
val thumb_w456: String?
}
}
CallerIDService.kt
package com.reactnativecallerid.service
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.Service
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.*
import android.provider.Settings
import android.telephony.TelephonyManager
import android.util.Log
import android.view.View
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import com.facebook.react.BuildConfig
import com.facebook.react.ReactActivity
import com.facebook.react.bridge.*
import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter
import com.google.gson.Gson
import com.google.gson.JsonObject
import com.reactnativecallerid.R
import com.reactnativecallerid.model.CallerIdVO
import com.reactnativecallerid.model.PushPayloadVO
import com.reactnativecallerid.model.PushPayloadVO.ActionVO
import com.reactnativecallerid.model.PushPayloadVO.ActionVO.OpenPage
import com.reactnativecallerid.model.TsReservation
class CallerIDService() : Service() {
var overlay: CallerIdOverlay? = CallerIdOverlay(this)
var statusCheckThread: Thread = object : Thread() {
override fun run() {
super.run()
try {
sleep(10000)
do {
sleep(1000)
} while (isOnTransaction || overlay != null && overlay!!.isShown)
} catch (e: InterruptedException) {
}
this#CallerIDService.stop()
}
}
override fun onCreate() {
super.onCreate()
if (BuildConfig.DEBUG) Log.d(TAG, "onCreate")
statusCheckThread.start()
showNoti(null)
overlay!!.onCreate()
}
override fun onDestroy() {
super.onDestroy()
overlay!!.onDestory()
statusCheckThread.interrupt()
}
override fun onBind(intent: Intent): IBinder? {
return null
}
#RequiresApi(Build.VERSION_CODES.M)
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
if (BuildConfig.DEBUG) Log.d(
TAG,
"onStartCommand :: action = " + intent.action + ", extras = " + bundle2string(intent.extras)
)
fun handleEvent(func: Unit) {
Handler(Looper.getMainLooper()).postDelayed({
func
}, 300)
}
if (intent != null) {
when (intent.action) {
TelephonyManager.ACTION_PHONE_STATE_CHANGED -> {
val state = intent.getStringExtra(TelephonyManager.EXTRA_STATE)
if (state != null) {
if (TelephonyManager.EXTRA_STATE_RINGING == state) {
val number = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER)
number?.let { handleEvent(procIncomingCallRinging(it)) }
} else if (TelephonyManager.EXTRA_STATE_OFFHOOK == state) {
val number = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER)
number?.let { handleEvent(procOffhook(it)) }
} else if (TelephonyManager.EXTRA_STATE_IDLE == state && TelephonyManager.EXTRA_STATE_RINGING == mPrevPhoneState) {
handleEvent(procIncomingCallRejected())
} else if (TelephonyManager.EXTRA_STATE_IDLE == state && TelephonyManager.EXTRA_STATE_OFFHOOK == mPrevPhoneState) {
handleEvent(procDisconnected())
} else if (TelephonyManager.EXTRA_STATE_IDLE == state) {
if (isOnTransaction) {
handleEvent(procDisconnected())
} else {
stop()
}
}
}
mPrevPhoneState = state
}
else -> stop()
}
}
return super.onStartCommand(intent, flags, startId)
}
fun stop() {
if (BuildConfig.DEBUG) Log.d(TAG, "!!!!!!!!STOP SERVICE!!!!!!!")
stopSelf()
}
private fun startTransaction(trid: String?, phonenumber: String?) {
if (trid == null || trid.isEmpty() || phonenumber == null || phonenumber.isEmpty()) {
return
}
mCurrentTrid = trid
mCurrentPhoneNumber = phonenumber
}
private fun endTransaction() {
mCurrentTrid = null
mCurrentPhoneNumber = null
}
private val isOnTransaction: Boolean
private get() = mCurrentTrid != null && mCurrentPhoneNumber != null
private fun procIncomingCallRinging(phonenumber: String?) {
Log.d(TAG, "!!!!!!!!procIncomingCallRinging!!!!!!!")
if (phonenumber == null || phonenumber.isEmpty()) {
stop()
return
}
val _phonenumber = phonenumber.replace("\\D+".toRegex(), "")
showNoti(null)
requestPutCallerid(
_phonenumber,
INCOMINGCALL_RINGING,
null,
object : IRequestPutCalleridCallback {
override fun onSuccess(trid: String?, userinfo: CallerIdOverlay.ICallerIdViewItem?) {
Log.d(TAG, "!!!!!!!!procIncomingCallRinging onSuccess CALL!!!!!!!trid: $trid userinfo : ${userinfo.toString()}")
mUserInfo = userinfo
showNoti(userinfo)
startTransaction(trid, _phonenumber)
if (userinfo == null) {
overlay!!.hideView()
endTransaction()
return
}
overlay!!.showRingingView(userinfo, mCurrentPhoneNumber)
}
})
}
private fun requestPutCallerid(
phonenumber: String?,
eventcode: Int,
trid: String?,
callback: IRequestPutCalleridCallback
) {
if (BuildConfig.DEBUG) Log.e(
TAG,
"requestPutCallerid() :: $phonenumber"
)
val args = JsonObject()
args.addProperty("phonenumber", phonenumber)
args.addProperty("eventcode", eventcode)
args.addProperty("trid", trid)
val prefs = getSharedPreferences(SHARED_PREFERENCES_NAME, 0)
val handle = prefs.getLong(BACKGROUND_SETUP_CALLBACK_HANDLE_KEY, 0L)
args.addProperty("callback", handle)
CALLERID_CALLBACK = callback
if (BuildConfig.DEBUG) Log.e(TAG, "invokeMethod() :: findCallerId :: " + args.toString())
if(!IsStart) {
startBackground(this)
IsStart = true
}
val map = Arguments.createMap()
map.putString("params",args.toString())
sendEvent("findCallerId",map)
}
enum class ViewType {
NONE, RINGING, CONNECTED, IDLE
}
interface IRequestPutCalleridCallback {
fun onSuccess(trid: String?, userinfo: CallerIdOverlay.ICallerIdViewItem?)
}
companion object {
var mPrevPhoneState = TelephonyManager.EXTRA_STATE_IDLE
private var mCurrentPhoneNumber: String? = null
private var mCurrentTrid: String? = null
private var mUserInfo: CallerIdOverlay.ICallerIdViewItem? = null
var mActivityContext : ReactActivity? = null
private const val TAG = "CallerIDService"
const val INCOMINGCALL_RINGING = 0
const val OUTGOINGCALL = 3
var IsStart = false
private var backgroundActivityView: View? = null
const val SHARED_PREFERENCES_NAME = "CallerIDService"
private const val BACKGROUND_SETUP_CALLBACK_HANDLE_KEY = "back" +
"ground_setup_callback"
private lateinit var mReactContext : ReactContext;
fun instance(_reactApplicationContext: ReactApplicationContext) {
mReactContext = _reactApplicationContext;
}
fun setActivity(_activity : ReactActivity) {
mActivityContext = _activity
}
#Synchronized
fun startBackground(context: Context?) {
IsStart = true
}
private fun sendEvent(eventName: String, params: WritableMap?) {
try {
mReactContext
.getJSModule(RCTDeviceEventEmitter::class.java)
.emit(eventName, params)
} catch (e: RuntimeException) {
Log.e(
"ERROR",
"java.lang.RuntimeException: Trying to invoke JS before CatalystInstance has been set!"
)
}
}
fun addEventListener(_method:String,value: ReadableMap) {
val json: String = value.toString()
if (_method == "findCallerResult") {
try {
val updateBundle = Arguments.toBundle(value)
updateBundle?.getString("trid")?.let { Log.d(TAG, "trid : $it") }
updateBundle?.getString("userinfo")?.let { Log.d(TAG, "userinfo : $it") }
Log.d(TAG,"carbrandname : ${Gson().fromJson(updateBundle?.getString("userinfo"),
CallerIdVO.CallerIdUserInfoVO::class.java).carbrandname}")
val infoJson = Gson().fromJson(updateBundle?.getString("userinfo"),
CallerIdVO.CallerIdUserInfoVO::class.java)
CALLERID_CALLBACK?.onSuccess(updateBundle?.getString("trid"), infoJson);
} catch (e: Exception) {
CALLERID_CALLBACK?.onSuccess(null, null);
}
} else if (_method == "findCallerResultShop") {
try {
val vo: TsReservation = Gson().fromJson(json, TsReservation::class.java)
val map = Arguments.createMap()
map.putString("techshop",Gson().toJson(vo,TsReservation::class.java))
CALLERID_CALLBACK?.onSuccess("techshop", vo);
} catch (e: Exception) {
sendEvent(_method,null)
}
}
}
fun bundle2string(bundle: Bundle?): String? {
if (bundle == null) {
return null
}
var string = "Bundle{"
for (key in bundle.keySet()) {
string += " " + key + " => " + bundle[key] + ";"
}
string += " }Bundle"
return string
}
var CALLERID_CALLBACK: IRequestPutCalleridCallback? = null
}
}
What problems can cause the following problems?
I'm not nunderstand
I am building an app that calls an activity to analyze a photo. once that activity starts it launches the camera or gallery depending on the value of "capture" or "gallery". the problem is:
I want to keep the activity orientation in portrait but the camera follows the phone orientation and after taking the photo it loses everything and starts the camera again OnResume again and again. if I held the phone vertically and captured the pic everything works fine and the pic appears in
Any changing of the rotation gets me error W/ImageView: Unable to open content: content://com.myProject.projecttwo.provider/external/Android/media/com.myProject.projecttwo/projectTwo/2021-07-31-17-59-19-4262257504715507656821.jpeg
import android.content.Context
import android.net.Uri
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.ImageView
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.FileProvider
import androidx.lifecycle.lifecycleScope
import java.io.File
import java.text.SimpleDateFormat
import java.util.*
class PhotoAnalysis : AppCompatActivity() {
private var receivedUriKey: Uri? = null
private lateinit var outputDirectory: File
//private var selection: String? = null
private var selection: String? = "capture" /* later will get it from clicks*/
private lateinit var imageView: ImageView
private val pickerContent = registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
if(uri != null) { receivedUriKey = uri}
}
private val capturePicture = registerForActivityResult(ActivityResultContracts.TakePicture()) {
if(it) {
receivedUriKey.let { uri ->
if( uri != null) {
receivedUriKey = uri
Log.d("Capture Pic", receivedUriKey.toString())
}
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_photo_analysis)
imageView = findViewById(R.id.result_image_view)
}
override fun onResume() {
super.onResume()
if( selection == "gallery" && receivedUriKey == null) {
pickerContent.launch("image/*")
} else if(selection == "capture" && receivedUriKey == null) {
Log.d("Capture Resume", receivedUriKey.toString())
takeImage()
}
if(receivedUriKey != null) {
Log.d("Capture Resume 2", receivedUriKey.toString())
imageView.setImageURI(receivedUriKey)
}
}
private fun takeImage() {
lifecycleScope.launchWhenStarted {
getTmpFileUri().let { uri ->
receivedUriKey = uri
capturePicture.launch(uri)
}
}
}
private fun getTmpFileUri(): Uri {
outputDirectory = getOutputDirectory(this)
val tmpFile = File.createTempFile(
SimpleDateFormat(FILENAME, Locale.ENGLISH).format(System.currentTimeMillis()), PHOTO_EXTENSION, outputDirectory).apply {
createNewFile()
deleteOnExit()
}
return FileProvider.getUriForFile(this, "${BuildConfig.APPLICATION_ID}.provider", tmpFile)
}
companion object {
private const val FILENAME = "yyyy-MM-dd-HH-mm-ss-SSS"
private const val PHOTO_EXTENSION = ".jpeg"
private fun getOutputDirectory(context: Context): File {
val appContext = context.applicationContext
val mediaDir = context.externalMediaDirs.firstOrNull()?.let {
File(it, appContext.resources.getString(R.string.app_name)).apply { mkdirs() } }
return if (mediaDir != null && mediaDir.exists())
mediaDir else appContext.filesDir
}
}
}
Im making a bluetooth app where you can turn on and off an arduino light. If i comment the setContentView, this does not happen. However, when I turn it on, it happens one of two things:
the app stops
it changes of activity
here's my code
package com.ainimei.remotemouse
import android.app.ProgressDialog
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothSocket
import android.content.Context
import android.os.AsyncTask
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AlertDialog
import kotlinx.android.synthetic.main.activity_control_bluetooth_connection.*
import java.io.IOException
import java.util.*
class ControlBluetoothConnection : AppCompatActivity() {
companion object {
var m_myUUID: UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")
var m_bluetoothSocket: BluetoothSocket? = null
lateinit var m_progress: ProgressDialog
lateinit var m_bluetoothAdapter: BluetoothAdapter
var m_isConnected: Boolean = false
lateinit var m_address: String
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_keyboard)
onCreateExtra()
}
private fun onCreateExtra() {
m_address = intent.getStringExtra(Connection.EXTRA_ADDRESS).toString()
ConnectToDevice(this).execute()
control_led_on.setOnClickListener { sendCommand("a") }
control_led_off.setOnClickListener { sendCommand("b") }
control_led_disconnect.setOnClickListener { disconnect() }
}
private fun sendCommand(input: String) {
if (m_bluetoothSocket != null) {
try{
m_bluetoothSocket!!.outputStream.write(input.toByteArray())
} catch(e: IOException) {
e.printStackTrace()
}
}
}
private fun disconnect() {
if (m_bluetoothSocket != null) {
try {
m_bluetoothSocket!!.close()
m_bluetoothSocket = null
m_isConnected = false
} catch (e: IOException) {
e.printStackTrace()
}
}
finish()
alertMessage("Disconnected Successfully", "Bluetooth")
}
private class ConnectToDevice(c: Context) : AsyncTask<Void, Void, String>() {
private var connectSuccess: Boolean = true
private val context: Context
init {
this.context = c
}
override fun onPreExecute() {
super.onPreExecute()
m_progress = ProgressDialog.show(context, "Connecting...", "please wait")
}
override fun doInBackground(vararg p0: Void?): String? {
try {
if (m_bluetoothSocket == null || !m_isConnected) {
m_bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
val device: BluetoothDevice = m_bluetoothAdapter.getRemoteDevice(m_address)
m_bluetoothSocket = device.createInsecureRfcommSocketToServiceRecord(m_myUUID)
BluetoothAdapter.getDefaultAdapter().cancelDiscovery()
m_bluetoothSocket!!.connect()
}
} catch (e: IOException) {
connectSuccess = false
e.printStackTrace()
}
return null
}
override fun onPostExecute(result: String?) {
super.onPostExecute(result)
if (!connectSuccess) {
//Log.i("data", "couldn't connect")
} else {
m_isConnected = true
}
m_progress.dismiss()
}
}
open fun alertMessage(message: String, title: String) {
var builder = AlertDialog.Builder(this)
builder.setTitle(title)
builder.setMessage(message)
val dialog = builder.create()
dialog.show()
}
}
i tried commenting some functions, and I saw that when i commented the onCreateExtra() function, this made the layout dont appear. need help
I am developing an audio player app that works well but I am facing one problem if I minimize the app it kill my foreground service. I don't know why it's happening can anyone suggest me any solution
MainActivity
import android.Manifest
import android.app.PendingIntent
import android.content.*
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.IBinder
import android.support.v4.media.MediaDescriptionCompat
import android.support.v4.media.MediaMetadataCompat
import android.support.v4.media.session.MediaSessionCompat
import android.text.Html
import android.util.Log
import android.view.WindowManager
import android.widget.SeekBar
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentTransaction
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import com.brahmakumaris.fragment.*
import com.brahmakumaris.model.getDashboard.RecentSong
import com.brahmakumaris.service.MusicPlayerService
import com.brahmakumaris.service.MyService
import com.brahmakumaris.util.*
import com.google.android.exoplayer2.DefaultLoadControl
import com.google.android.exoplayer2.ExoPlaybackException
import com.google.android.exoplayer2.Player
import com.google.android.exoplayer2.SimpleExoPlayer
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector
import com.google.android.exoplayer2.ext.mediasession.TimelineQueueNavigator
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory
import com.google.android.exoplayer2.source.ConcatenatingMediaSource
import com.google.android.exoplayer2.source.ProgressiveMediaSource
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector
import com.google.android.exoplayer2.ui.PlayerNotificationManager
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory
import com.google.android.exoplayer2.util.Util
import kotlinx.android.synthetic.main.activity_main.*
import java.util.*
import kotlin.collections.ArrayList
class MainActivity : AppCompatActivity(), OnFragmentInteractionListener {
override fun onFragmentInteraction(screen: String, model: RecentSong, songList: ArrayList<RecentSong>, position: Int) {
MyLog.e(TAG, screen)
when (screen) {
getString(R.string.speakers) -> {
bottom_navigation.selectedItemId = R.id.nav_speaker
supportFragmentManager.switch(
newFrag = SpeakerPageFragment.newInstance(),
tag = getString(R.string.speakers)
)
}
getString(R.string.classes) -> {
bottom_navigation.selectedItemId = R.id.nav_class
supportFragmentManager.switch(
newFrag = ClassesPageFragment.newInstance(),
tag = getString(R.string.classes)
)
}
getString(R.string.songs) -> {
bottom_navigation.selectedItemId = R.id.nav_song
supportFragmentManager.switch(
newFrag = SongsPageFragment.newInstance(),
tag = getString(R.string.songs)
)
}
getString(R.string.play_song) -> {
if(!model.name.isNullOrBlank()) {
songPosition = position
mSongList = songList
MyLog.e(TAG, "======= ${getString(R.string.play_song)} ${model.name}")
isPlaying = false // to start new song
// play song
if (!lnPlayer.isVisible) {
lnPlayer.isVisible = true
}
titleTxt.setHtmlText(model.name)
if(mBound) {
startService()
mMusicPlayerService.playSong(mSongList,songPosition)
media_button.setImageResource(R.drawable.ic_pause_black_24dp)
}
setPlayPause(!mMusicPlayerService.isPlaying())
initSeekBar()
}
}
else -> {
}
}
}
private val TAG = javaClass.simpleName
private var isPlaying = false
private var mediaSource: ProgressiveMediaSource? = null
// notification
private lateinit var mediaSessionConnector: MediaSessionConnector
private lateinit var mediaSession: MediaSessionCompat
private lateinit var playerNotificationManager: PlayerNotificationManager
private var handler: Handler? = null
private val dashUrl = "http://www.panacherock.com/downloads/mp3/01_All_Tangled_Up.mp3"
var mSongList: ArrayList<RecentSong> = ArrayList()
var songPosition = 0
val MESSAGE_KEY = "message_key"
private lateinit var mMusicPlayerService:MusicPlayerService
private lateinit var mPlayer: SimpleExoPlayer
private var mBound = false
private val mServiceConnection: ServiceConnection = object : ServiceConnection {
override fun onServiceConnected(componentName: ComponentName, iBinder: IBinder) {
val binder = iBinder as MusicPlayerService.MyServiceBinder
mMusicPlayerService = binder.getService()
mPlayer = mMusicPlayerService.getPlayerInstance()!!
mPlayer.addListener(playerListener)
mBound = true
MyLog.e(TAG,"onServiceConnected: ")
}
override fun onServiceDisconnected(componentName: ComponentName) {
mBound = false
MyLog.e(TAG,"onServiceDisconnected: ") // calles only in rare case if service destroy unexpectedly
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
if (savedInstanceState == null) {
supportFragmentManager.switch(
newFrag = DashboardPageFragment.newInstance(),
tag = getString(R.string.home)
)
}
getIntentData()
bottom_navigation.setOnNavigationItemSelectedListener { item ->
hideKeybord()
when(item.itemId) {
R.id.nav_home -> {
checkFragment()
supportFragmentManager.switch(
newFrag = DashboardPageFragment.newInstance(),
tag = getString(R.string.home)
)
true
}
R.id.nav_song -> {
checkFragment()
supportFragmentManager.switch(
newFrag = SongsPageFragment.newInstance(),
tag = getString(R.string.songs)
)
true
}
R.id.nav_speaker -> {
checkFragment()
supportFragmentManager.switch(
newFrag = SpeakerPageFragment.newInstance(),
tag = getString(R.string.speakers)
)
true
}
R.id.nav_class -> {
checkFragment()
supportFragmentManager.switch(
newFrag = ClassesPageFragment.newInstance(),
tag = getString(R.string.classes)
)
true
}
R.id.nav_search -> {
checkFragment()
supportFragmentManager.switch(
newFrag = SearchPageFragment.newInstance(),
tag = getString(R.string.search)
)
true
}
else -> false
}
}
bottom_navigation.setOnNavigationItemReselectedListener { } //disable reselection tab
media_button.setOnClickListener {
// startService()
setPlayPause(!isPlaying)
}
imgClose.setOnClickListener {
isPlaying = true // to stop song
playerNotificationManager.setPlayer(null)
setPlayPause(!isPlaying)
if (lnPlayer.isVisible) {
lnPlayer.isVisible = false
}
}
}
private fun getIntentData() {
if (intent!=null && intent.hasExtra("internet") && !intent.getBooleanExtra("internet", false)) {
this.changeFragment(
DownloadPageFragment.newInstance(), Constants.DOWNLOAD_TAG
)
}
}
private fun checkFragment() {
val fragment = getSupportFragmentManager().findFragmentByTag(Constants.SUB_CATEGORY_TAG)
if (fragment != null) {
getSupportFragmentManager().beginTransaction().remove(fragment).commit()
}
val fragment2 = getSupportFragmentManager().findFragmentByTag(Constants.DOWNLOAD_TAG)
if (fragment2 != null) {
getSupportFragmentManager().beginTransaction().remove(fragment2).commit()
}
}
private val playerListener by lazy {
object : Player.EventListener {
override fun onPlayerError(error: ExoPlaybackException) {
super.onPlayerError(error)
//onError(error)
}
override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {
super.onPlayerStateChanged(playWhenReady, playbackState)
when (playbackState) {
Player.STATE_BUFFERING -> Log.e(TAG,"STATE_BUFFERING")
Player.STATE_ENDED -> Log.e(TAG,"STATE_ENDED")
Player.STATE_IDLE -> Log.e(TAG,"STATE_IDLE")
Player.STATE_READY -> {
// setPlayPause(playWhenReady)
isPlaying = playWhenReady
mPlayer.setPlayWhenReady(playWhenReady)
if (!isPlaying) {
media_button.setImageResource(R.drawable.ic_play_arrow_black_24dp)
} else {
setProgress()
media_button.setImageResource(R.drawable.ic_pause_black_24dp)
}
if (playWhenReady) {
Log.e(TAG, "PlaybackStatus.PLAYING")
} else {
Log.e(TAG, "PlaybackStatus.PAUSED")
}
titleTxt.setHtmlText(mSongList[mPlayer.currentWindowIndex].name)
MyLog.e(TAG, "====== " + mSongList[mPlayer.currentWindowIndex].name)
MyLog.e(TAG, "======111 " + mSongList[mPlayer.currentWindowIndex].descripation)
}
else -> Log.e(TAG, "PlaybackStatus.IDLE")
}
}
}
}
private fun startService() {
val myService = Intent(this, MusicPlayerService ::class.java)
Util.startForegroundService(this,myService)
}
private fun stopService() {
val myService = Intent(this, MusicPlayerService ::class.java)
stopService(myService)
}
private fun setPlayPause(play: Boolean) {
if(mBound) {
if(mMusicPlayerService.isPlaying()) {
mMusicPlayerService.pause()
media_button.setImageResource(R.drawable.ic_play_arrow_black_24dp)
} else {
startService()
playerNotificationManager = mMusicPlayerService.getNotificationInstance()!!
/* if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(intent)
} else {
startService(intent)
}*/
mMusicPlayerService.play()
setProgress()
media_button.setImageResource(R.drawable.ic_pause_black_24dp)
}
}
/*isPlaying = play
exoPlayer.setPlayWhenReady(play)
if (!isPlaying) {
media_button.setImageResource(R.drawable.ic_play_arrow_black_24dp)
} else {
setProgress()
media_button.setImageResource(R.drawable.ic_pause_black_24dp)
}*/
}
private fun stringForTime(timeMs: Int): String {
val mFormatBuilder: StringBuilder
val mFormatter: Formatter
mFormatBuilder = StringBuilder()
mFormatter = Formatter(mFormatBuilder, Locale.getDefault())
val totalSeconds = timeMs / 1000
val seconds = totalSeconds % 60
val minutes = totalSeconds / 60 % 60
val hours = totalSeconds / 3600
mFormatBuilder.setLength(0)
return if (hours > 0) {
mFormatter.format("%d:%02d:%02d", hours, minutes, seconds).toString()
} else {
mFormatter.format("%02d:%02d", minutes, seconds).toString()
}
}
private fun setProgress() {
seekPlayerProgress.progress = 0
seekPlayerProgress.max = mPlayer.getDuration().toInt() / 1000
position.setText(stringForTime(mPlayer.getCurrentPosition().toInt()))
duration.setText(stringForTime(mPlayer.getDuration().toInt()))
if (handler == null) handler = Handler()
//Make sure you update Seekbar on UI thread
handler!!.post(object : Runnable {
override fun run() {
if (mPlayer != null && ::mPlayer.isInitialized && isPlaying) {
seekPlayerProgress.max = mPlayer.getDuration().toInt() / 1000
val mCurrentPosition = mPlayer.getCurrentPosition().toInt() / 1000
seekPlayerProgress.progress = mCurrentPosition
position.setText(stringForTime(mPlayer.getCurrentPosition().toInt()))
duration.setText(stringForTime(mPlayer.getDuration().toInt()))
handler!!.postDelayed(this, 1000)
}
}
})
}
private fun initSeekBar() {
seekPlayerProgress.requestFocus()
seekPlayerProgress.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
if (!fromUser) {
// We're not interested in programmatically generated changes to
// the progress bar's position.
return
}
mPlayer.seekTo((progress * 1000).toLong())
}
override fun onStartTrackingTouch(seekBar: SeekBar) {
}
override fun onStopTrackingTouch(seekBar: SeekBar) {
}
})
seekPlayerProgress.setMax(0)
seekPlayerProgress.setMax(mPlayer.getDuration().toInt() / 1000)
}
private var doubleBackToExitPressedOnce = false
override fun onBackPressed() {
val fragment = getSupportFragmentManager().findFragmentByTag(Constants.SUB_CATEGORY_TAG)
if (fragment != null) {
getSupportFragmentManager().beginTransaction().remove(fragment).commit()
return
}
val fragment2 = getSupportFragmentManager().findFragmentByTag(Constants.DOWNLOAD_TAG)
if (fragment2 != null) {
getSupportFragmentManager().beginTransaction().remove(fragment2).commit()
return
}
if (doubleBackToExitPressedOnce) {
super.onBackPressed()
return
}
this.doubleBackToExitPressedOnce = true
this.showSnackBarToast("Please click BACK again to exit")
Handler().postDelayed(Runnable { doubleBackToExitPressedOnce = false }, 2000)
}
override fun onDestroy() {
if(::playerNotificationManager.isInitialized) {
playerNotificationManager.setPlayer(null)
}
killPlayer()
// stopService()
MyLog.e(TAG," #### onDestroy #### ")
super.onDestroy()
}
override fun onStop() {
super.onStop()
if(mBound) {
unbindService(mServiceConnection)
mBound = false
}
LocalBroadcastManager.getInstance(this)
.unregisterReceiver(broadCastReceiver)
MyLog.e(TAG," #### onStop #### ")
}
private fun killPlayer() {
if (mPlayer != null) {
mPlayer.release()
mediaSource = null
}
MyLog.e(TAG,"#### killPlayer ####")
}
private fun getHtmlText(str:String):String {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
return (Html.fromHtml(str, Html.FROM_HTML_MODE_COMPACT)).toString()
} else {
return (Html.fromHtml(str)).toString()
}
}
private fun setMediaSession() {
mediaSession = MediaSessionCompat(this#MainActivity,"MEDIA_SESSION_TAG")
mediaSession.isActive = true
playerNotificationManager.setMediaSessionToken(mediaSession.sessionToken) //enhance media stye notification and provide artwork in lock screen
mediaSessionConnector = MediaSessionConnector(mediaSession)
//timeline is the internal representation of the pllaylist after the player has been prepared
mediaSessionConnector.setQueueNavigator(object : TimelineQueueNavigator(mediaSession){
override fun getMediaDescription(player: Player?, windowIndex: Int): MediaDescriptionCompat {
return getMediaDescriptionData(this#MainActivity, mSongList[windowIndex])
}
})
mediaSessionConnector.setPlayer(exoPlayer/*, null*/) //sync player wth media session
}
fun getMediaDescriptionData(context: Context, sample: RecentSong): MediaDescriptionCompat {
val extras = Bundle()
val options = BitmapFactory.Options()
options.inSampleSize = 8
// val bitmap = BitmapFactory.decodeFile(getBitmap(context, sample.bitmapResource), options)
val bitmap = context.getBitmap(R.drawable.bg)
extras.putParcelable(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, bitmap)
extras.putParcelable(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON, bitmap)
return MediaDescriptionCompat.Builder()
.setMediaId(sample.song)
.setIconBitmap(bitmap)
.setTitle(sample.name)
.setDescription(sample.descripation)
.setExtras(extras)
.build()
}
override fun onStart() {
super.onStart()
bindService(Intent(this,MusicPlayerService::class.java),mServiceConnection,Context.BIND_AUTO_CREATE)
LocalBroadcastManager.getInstance(this)
.registerReceiver(broadCastReceiver, IntentFilter(MusicPlayerService().MUSIC_COMPLETED))
}
val broadCastReceiver = object : BroadcastReceiver() {
override fun onReceive(contxt: Context?, intent: Intent?) {
MyLog.e(TAG,"onReceive: ${intent?.getBooleanExtra(MESSAGE_KEY,false)}")
if(intent!!.getBooleanExtra(MESSAGE_KEY,false)) {
setPlayPause(intent.getBooleanExtra(MESSAGE_KEY,false))
if (intent.getBooleanExtra(MESSAGE_KEY,false)) {
Log.e(TAG, "PlaybackStatus.PLAYING")
} else {
Log.e(TAG, "PlaybackStatus.PAUSED")
}
titleTxt.setHtmlText(mSongList[mPlayer.currentWindowIndex].name)
MyLog.e(TAG,"====== "+mSongList[mPlayer.currentWindowIndex].name)
MyLog.e(TAG,"======111 "+mSongList[mPlayer.currentWindowIndex].descripation)
}
}
}
}
MusicPlayerService
import android.app.PendingIntent
import android.app.Service
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.Binder
import android.os.IBinder
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import com.brahmakumaris.MainActivity
import com.brahmakumaris.R
import com.brahmakumaris.model.getDashboard.RecentSong
import com.brahmakumaris.util.MyLog
import com.brahmakumaris.util.getBitmap
import com.brahmakumaris.util.getPlaintextfromHtmlHtmlText
import com.bumptech.glide.Glide
import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.transition.Transition
import com.google.android.exoplayer2.Player
import com.google.android.exoplayer2.SimpleExoPlayer
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory
import com.google.android.exoplayer2.source.ConcatenatingMediaSource
import com.google.android.exoplayer2.source.ProgressiveMediaSource
import com.google.android.exoplayer2.ui.PlayerNotificationManager
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory
import com.google.android.exoplayer2.util.Util
class MusicPlayerService : Service() {
private val TAG = javaClass.simpleName
private val mContext: Context = this
private val mBinder = MyServiceBinder()
val MUSIC_COMPLETED = "music completed"
val mPlayer: SimpleExoPlayer by lazy { SimpleExoPlayer.Builder(this).build() }
private lateinit var playerNotificationManager: PlayerNotificationManager
var mSongList: ArrayList<RecentSong> = ArrayList()
override fun onCreate() {
super.onCreate()
MyLog.d(TAG,"onCreate: ")
}
fun playSong(mSongList: ArrayList<RecentSong> = ArrayList(), position: Int = 0)/* mContext: Context = this*/ {
this.mSongList = mSongList
val dataSourceFactory = DefaultDataSourceFactory(mContext, Util.getUserAgent(mContext,getString(R.string.app_name)))
val concateMediaSource = ConcatenatingMediaSource()
for (i in mSongList) {
val mediaSource = ProgressiveMediaSource
.Factory(
DefaultDataSourceFactory(mContext, dataSourceFactory),
DefaultExtractorsFactory()
)
.createMediaSource(/*i.uri*/Uri.parse(i.musicFile))
concateMediaSource.addMediaSource(mediaSource)
}
mPlayer.prepare(concateMediaSource)
mPlayer.seekToDefaultPosition(position)
mPlayer.playWhenReady =true
setNotification()
}
private fun setNotification() {
playerNotificationManager = PlayerNotificationManager.createWithNotificationChannel(
this,"channel_id",R.string.channelName,R.string.channelDescription,11,
object : PlayerNotificationManager.MediaDescriptionAdapter{
override fun createCurrentContentIntent(player: Player): PendingIntent? {
val intent = Intent(mContext, MainActivity::class.java)
return PendingIntent.getActivity(mContext,0,intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
override fun getCurrentContentText(player: Player): String? {
// return mSongList[player.currentWindowIndex].descripation // descrption
return mSongList[player.currentWindowIndex].descripation.getPlaintextfromHtmlHtmlText() // descrption
}
override fun getCurrentContentTitle(player: Player): String {
// return mSongList[player.currentWindowIndex].name // title
return mSongList[player.currentWindowIndex].name.getPlaintextfromHtmlHtmlText()
}
override fun getCurrentLargeIcon(
player: Player,
callback: PlayerNotificationManager.BitmapCallback
): Bitmap? {
return mContext.getBitmap(R.drawable.bg)
}
} ,object : PlayerNotificationManager.NotificationListener {
override fun onNotificationStarted(notificationId: Int, notification: Notification) {
startForeground(notificationId,notification)
}
override fun onNotificationPosted(notificationId: Int, notification: Notification, ongoing: Boolean) {
startForeground(notificationId,notification)
}
override fun onNotificationCancelled(notificationId: Int, dismissedByUser: Boolean) {
stopSelf()
}
override fun onNotificationCancelled(notificationId: Int) {
stopSelf()
}
}
)
//show hide button
playerNotificationManager.setUseStopAction(false) //stop song
playerNotificationManager.setRewindIncrementMs(0) //hide rewind button
playerNotificationManager.setFastForwardIncrementMs(0) //hide fast forward button
playerNotificationManager.setPlayer(mPlayer)
}
inner class MyServiceBinder : Binder() {
fun getService(): MusicPlayerService = this#MusicPlayerService
}
fun getPlayerInstance(): SimpleExoPlayer? {
return mPlayer
}
fun getNotificationInstance(): PlayerNotificationManager? {
return playerNotificationManager
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
MyLog.d(TAG,"onStartCommand: ")
return START_NOT_STICKY
}
override fun onBind(intent: Intent?): IBinder? {
MyLog.d(TAG,"onBind: ")
return mBinder
}
override fun onUnbind(intent: Intent?): Boolean {
MyLog.d(TAG,"onUnbind: ")
return true
}
override fun onRebind(intent: Intent?) {
MyLog.d(TAG,"onRebind: ")
super.onRebind(intent)
}
override fun onDestroy() {
MyLog.e(TAG,"onDestroy: ")
super.onDestroy()
mPlayer.release()
if(::playerNotificationManager.isInitialized) {
playerNotificationManager.setPlayer(null)
}
}
// public client method
fun isPlaying():Boolean {
return mPlayer.isPlaying
}
fun play() {
mPlayer.setPlayWhenReady(true)
}
fun pause() {
mPlayer.setPlayWhenReady(false)
}
}
if I minimize the app then it's printing unbind and then it directly going to onDestroy why it's happening can anyone help me,
Any Help Would Be Highly Appreciated.
I just remove onStop unbind and unregister code and set in onDestroy and it's working for me.
You should be using startForeground() with a notification, to Android service that never stops running.
startForeground(1, notification)
Please have a look at this.
https://robertohuertas.com/2019/06/29/android_foreground_services/
I hope this will help you.
I experienced this issue because I set the player on notification manager to null on onStop which causes onNotificationCancelled to be called, you should check, if the notification was canceled by the user then you should stop the service, else leave it running.
override fun onNotificationCancelled(notificationId: Int, dismissedByUser:Boolean)
{
if (dismissedByUser) {
stopSelf()
}
}
I would like to create and store new users also update the existing users in the following code
What code needs to be added to strore new users in a SQLitedatabase
I have a sqllitehelper class
which has adduser,updateuser,and readuser methods
From what i understand ,the signinfragment activity stores the instance of the logged in user and
if the instance exists then its loaded.When we logout we basically have to make a new user and we login
i would like to create,store,update users using an SQLite database.
package com.google.samples.apps.topeka.fragment
import android.annotation.TargetApi
import android.content.ContentValues
import android.content.Context
import android.content.Intent
import android.database.sqlite.SQLiteDatabase
import android.os.Build
import android.os.Bundle
import android.support.design.widget.FloatingActionButton
import android.support.v4.app.ActivityOptionsCompat
import android.support.v4.app.Fragment
import android.support.v4.util.Pair
import android.support.v4.view.ViewCompat
import android.support.v4.view.animation.FastOutSlowInInterpolator
import android.text.Editable
import android.text.TextWatcher
import android.transition.Transition
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.EditText
import android.widget.GridView
import android.widget.Toast
import android.widget.Toast.LENGTH_LONG
import com.google.samples.apps.topeka.activity.SignInActivity
import com.google.samples.apps.topeka.adapter.AvatarAdapter
import com.google.samples.apps.topeka.base.R
import com.google.samples.apps.topeka.helper.ActivityLaunchHelper
import com.google.samples.apps.topeka.helper.ApiLevelHelper
import com.google.samples.apps.topeka.helper.DefaultLogin
import com.google.samples.apps.topeka.helper.TAG
import com.google.samples.apps.topeka.helper.TransitionHelper
import com.google.samples.apps.topeka.helper.isLoggedIn
import com.google.samples.apps.topeka.helper.login
import com.google.samples.apps.topeka.helper.onLayoutChange
import com.google.samples.apps.topeka.helper.onSmartLockResult
import com.google.samples.apps.topeka.model.Avatar
import com.google.samples.apps.topeka.model.Player
import com.google.samples.apps.topeka.persistence.PPlayer
import com.google.samples.apps.topeka.widget.TextWatcherAdapter
import com.google.samples.apps.topeka.widget.TransitionListenerAdapter
import com.google.samples.apps.topeka.persistence.TopekaDatabaseHelper;
/**
* Enable selection of an [Avatar] and user name.
*/
class SignInFragment : Fragment() {
private var firstNameView: EditText? = null
private var lastInitialView: EditText? = null
private var doneFab: FloatingActionButton? = null
private var avatarGrid: GridView? = null
private var firstName = ""
private var lastInitial= ""
private var avatar = ""
private val edit by lazy { arguments?.getBoolean(ARG_EDIT, false) ?: false }
private var selectedAvatarView: View? = null
private var player: Player? = null
private var selectedAvatar: Avatar? = null
var a = getContext()
override fun onCreate(savedInstanceState: Bundle?) {
var a = context
val resources = context!!.resources
var ss = TopekaDatabaseHelper(requireActivity())
val newValues = ContentValues().apply {
// Sets the values of each column and inserts the value.
// The arguments to the "put"
// method are "column name" and "value"
}
if (savedInstanceState != null) {
val avatarIndex = savedInstanceState.getInt(KEY_SELECTED_AVATAR_INDEX)
if (avatarIndex != GridView.INVALID_POSITION) {
selectedAvatar = Avatar.values()[avatarIndex]
}
}
activity?.run {
if (isLoggedIn()) {
navigateToCategoryActivity()
Toast.makeText(requireContext(),"old", LENGTH_LONG)
} else {
maketext("new player")
login.loginPlayer(this, ::onSuccessfulLogin)
}
}
super.onCreate(savedInstanceState)
}
/**
* Called when logged in successfully.
*/
private fun onSuccessfulLogin(player: Player) {
if (login != DefaultLogin) return
this.player = player
if (edit) {
with(player) {
firstNameView?.setText(player.firstName)
lastInitialView?.run {
setText(player.lastInitial)
requestFocus()
setSelection(length())
var db = TopekaDatabaseHelper(context)
db.adduser(player.firstName,player.lastInitial)
maketext("saved new")
}
this#SignInFragment.player = player.also {
if (activity != null)
login.savePlayer(activity!!, this, { selectAvatar(it.avatar!!) })
maketext("saved new")
}
}
} else {
Toast.makeText(requireContext(),"new", LENGTH_LONG)
navigateToCategoryActivity()
}
}
private fun maketext(ss:String){
Toast.makeText(requireContext(),ss,LENGTH_LONG)
}
private fun navigateToCategoryActivity() {
activity?.run {
ActivityLaunchHelper.launchCategorySelection(this)
supportFinishAfterTransition()
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
activity?.onSmartLockResult(
requestCode,
resultCode,
data,
success = {
player = it
initContents()
navigateToCategoryActivity()
},
failure = {
activity?.run {
login.loginPlayer(this, ::onSuccessfulLogin)
}
}
)
super.onActivityResult(requestCode, resultCode, data)
}
override fun onCreateView(inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?): View? {
val contentView = inflater.inflate(R.layout.fragment_sign_in, container, false)
contentView.onLayoutChange {
avatarGrid?.apply {
adapter = AvatarAdapter(activity!!)
onItemClickListener = AdapterView.OnItemClickListener { _, view, position, _ ->
selectedAvatarView = view
selectedAvatar = Avatar.values()[position]
// showing the floating action button if input data is valid
showFab()
}
numColumns = calculateSpanCount()
selectedAvatar?.run { selectAvatar(this) }
}
}
return contentView
}
/**
* Calculates spans for avatars dynamically.
* #return The recommended amount of columns.
*/
private fun calculateSpanCount(): Int {
val avatarSize = resources.getDimensionPixelSize(R.dimen.size_fab)
val avatarPadding = resources.getDimensionPixelSize(R.dimen.spacing_double)
return (avatarGrid?.width ?: 0) / (avatarSize + avatarPadding)
}
override fun onSaveInstanceState(outState: Bundle) {
outState.putInt(KEY_SELECTED_AVATAR_INDEX, (avatarGrid?.checkedItemPosition ?: 0))
super.onSaveInstanceState(outState)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
firstNameView = view.findViewById<EditText>(R.id.first_name)
lastInitialView = view.findViewById<EditText>(R.id.last_initial)
doneFab = view.findViewById<FloatingActionButton>(R.id.done)
avatarGrid = view.findViewById<GridView>(R.id.avatars)
if (edit || (player != null && player!!.valid())) {
initContentViews()
initContents()
}
hideEmptyView()
super.onViewCreated(view, savedInstanceState)
}
private fun hideEmptyView() {
view?.run {
findViewById<View>(R.id.empty).visibility = View.GONE
findViewById<View>(R.id.content).visibility = View.VISIBLE
}
}
private fun initContentViews() {
val textWatcher = object : TextWatcher by TextWatcherAdapter {
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
// hiding the floating action button if text is empty
if (s.isEmpty()) {
doneFab?.hide()
}
}
// showing the floating action button if avatar is selected and input data is valid
override fun afterTextChanged(s: Editable) {
if (isAvatarSelected() && isInputDataValid()) doneFab?.show()
}
}
firstNameView?.addTextChangedListener(textWatcher)
lastInitialView?.addTextChangedListener(textWatcher)
doneFab?.setOnClickListener {
if (it.id == R.id.done) {
val first = firstNameView?.text?.toString()
val last = lastInitialView?.text?.toString()
activity?.run {
val toSave = player?.apply {
// either update the existing player object
firstName = first
lastInitial = last
avatar = selectedAvatar
} ?: Player(first, last, selectedAvatar) /* or create a new one */
login.savePlayer(this, toSave) {
Toast.makeText(this,"done",LENGTH_LONG)
Log.d(TAG, "Saving login info successful.")
}
}
}
removeDoneFab {
performSignInWithTransition(selectedAvatarView
?: avatarGrid?.getChildAt(selectedAvatar!!.ordinal))
}
}
}
private fun removeDoneFab(endAction: () -> Unit) {
ViewCompat.animate(doneFab)
.scaleX(0f)
.scaleY(0f)
.setInterpolator(FastOutSlowInInterpolator())
.withEndAction(endAction)
.start()
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
private fun performSignInWithTransition(v: View? = null) {
if (v == null || ApiLevelHelper.isLowerThan(Build.VERSION_CODES.LOLLIPOP)) {
// Don't run a transition if the passed view is null
activity?.run {
navigateToCategoryActivity()
}
return
}
if (ApiLevelHelper.isAtLeast(Build.VERSION_CODES.LOLLIPOP)) {
activity?.run {
window.sharedElementExitTransition.addListener(object :
Transition.TransitionListener by TransitionListenerAdapter {
override fun onTransitionEnd(transition: Transition) {
finish()
}
})
val pairs = TransitionHelper.createSafeTransitionParticipants(this, true,
Pair(v, getString(R.string.transition_avatar)))
val options = ActivityOptionsCompat.makeSceneTransitionAnimation(this, *pairs)
ActivityLaunchHelper.launchCategorySelection(this, options)
}
}
}
private fun initContents() {
player?.run {
valid().let {
firstNameView?.setText(firstName)
lastInitialView?.setText(lastInitial)
avatar?.run { selectAvatar(this) }
}
}
}
private fun isAvatarSelected() = selectedAvatarView != null || selectedAvatar != null
private fun selectAvatar(avatar: Avatar) {
selectedAvatar = avatar
avatarGrid?.run {
requestFocusFromTouch()
setItemChecked(avatar.ordinal, true)
}
showFab()
}
private fun showFab() {
if (isInputDataValid()) doneFab?.show()
}
private fun isInputDataValid() =
firstNameView?.text?.isNotEmpty() == true &&
lastInitialView?.text?.isNotEmpty() == true &&
selectedAvatar != null
companion object {
private const val ARG_EDIT = "EDIT"
private const val KEY_SELECTED_AVATAR_INDEX = "selectedAvatarIndex"
fun newInstance(edit: Boolean = false): SignInFragment {
return SignInFragment().apply {
arguments = Bundle().apply {
putBoolean(ARG_EDIT, edit)
}
}
}
}
}