I have been working on an app that plays some audio. I am currently playing the audio as a STREAM_MUSIC type of stream and this works just fine. I want to be able to control the volume with the hardware volume controls on the device. When I am in the app the hardware buttons don't do anything, the volume doesn't change and the toast doesn't pop up. I then press the home button so the app is running in the background the hardware volume buttons work. They only work when my app is running in the background.
I have tried to use the code this.setVolumeControlStream(AudioManager.STREAM_MUSIC); in my onCreate() method and this did not change the apps behavior and I am still facing the same problems.
I also have been testing this on a DROID 2, DROID RAZR, Samsung Galaxy s3, Samsung Galaxy s4, Lenovo tablet, and a rooted DROID 2 but they all behave the same.
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
AudioManager audio = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
setVolumeControlStream(audio.STREAM_MUSIC); //this line should set up the hardware
//buttons to control the volume
if (QtApplication.m_delegateObject != null && QtApplication.onCreate != null) {
QtApplication.invokeDelegateMethod(QtApplication.onCreate, savedInstanceState);
return;
}
requestWindowFeature(Window.FEATURE_NO_TITLE);
try {
m_activityInfo = getPackageManager().getActivityInfo(getComponentName(), PackageManager.GET_META_DATA);
} catch (NameNotFoundException e) {
e.printStackTrace();
finish();
return;
}
if (null == getLastNonConfigurationInstance()) {
// if splash screen is defined, then show it
if (m_activityInfo.metaData.containsKey("android.app.splash_screen") )
setContentView(m_activityInfo.metaData.getInt("android.app.splash_screen"));
startApp(true);
}
}
You may be tempted to try and listen for volume key presses and modify the volume of your audio stream that way. Resist the urge. Android provides the handy setVolumeControlStream() method to direct volume key presses to the audio stream you specify.
Take a look at this, I think it might be helpful:
Use Hardware Volume Keys to Control Your App’s Audio Volume
EDIT:
on your oncreate method you have to do:
this.setVolumeControlStream(AudioManager.STREAM_MUSIC); //if you use AudioManager.STREAM_MUSIC to load the sound
soundPool = new SoundPool(10, AudioManager.STREAM_MUSIC, 0);
soundPool.setOnLoadCompleteListener(new OnLoadCompleteListener() {
#Override
public void onLoadComplete(SoundPool soundPool, int sampleId,
int status) {
loaded = true;
}
});
soundPool.load(this, R.raw.sound1, 1); // your sound
Related
I'm developing an application with playing audio. In several cases I change the AudioStreamType to AudioManager.STREAM_RING(is mode when music is playing both: speakers and headset). When I use Bluetooth headset, I have a small annoying delay.
So i was reading that Bluetooth has a buffer and and this is logical
, but how I can solve this? Also i tried to change buffer size or delay for mediaPlayer.
So, i create a mediaPlayer like as:
#Override
public void onInit() {
mediaPlayer = new MediaPlayer();
mediaPlayer.setOnCompletionListener(this);
mediaPlayer.setLooping(true);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_RING);
songManager = new SongsManager(context);
}
#Override
public void onPrepare() {
// prepare media player
if (mediaPlayer != null) {
mediaPlayer.reset();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_RING);
absolutePathToPlayingSong = /*some place*/;
mediaPlayer.setDataSource(/*some place*/);
mediaPlayer.prepare();
mediaPlayer.setVolume(volumeLvl, volumeLvl);
}
AudioManager audio = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
audio.setStreamVolume(AudioManager.STREAM_MUSIC, 20, 0);
}
then i just start player:
mediaPlayer.start();
So, i already tried:
to change a prepare() to prepareAsync() - probably it was tiny help, to may be i had a sound hallucinations. Unfortunately it broke a seekTo() in one place
added onPrepared() and start playing from listener - I not sure that it help
Give me please any advance^ how to fix delay for Bluetooth headset? I checked this device in YouTube application and it work great. So problem in my application. sorry my bad English!)
I have 2 target devices android 7.0(SDK 24) and android 4.2 (SDK 16)
I am using the original Music player in android Nougat, while the music is playing in the Lock Screen Appear an animation in the Buttom like this screenshot.
But when i using my own App Media Player in the same Android Nougat and Same device in the Lock Screen dont appear that animation.
The question is: How can i Add that animation in my Media Player App? it´s not a gif image because The animation moves to the rhythm of the music.
**This is my Notification Method ** if i am missing something or if i have to add something else.
ublic void Custom_Notificacion(){
Notification notification = new Notification(R.drawable.logobubble, null, System.currentTimeMillis());
notificationView = new RemoteViews(getPackageName(), R.layout.layout_notificacion_personalizada);
notificationView.setImageViewBitmap(R.id.id_FotoAlbumNotif,FotoNotif);
notificationView.setTextViewText(R.id.id_NombreMp3Notif,NommbreArtista);
notificationView.setTextViewText(R.id.id_NombreCancionNotif,NombreCancion);
notification.contentView = notificationView;
notification.flags |= Notification.FLAG_NO_CLEAR;
startForeground(constantes.NOTIFICATION_ID.FOREGROUND_SERVICE,notification);
}
I've read an article about this,an feasible solution is custom a lock screen page and display the Animation view within it,to achieve this you need a Service listening to the LOCK_SCREEN Broadcast,and start your LockScreenActivity ;replace the system lock screen at the same time.
here is some code segment might be helpful:
Register Broadcast Receiver
IntentFilter mScreenOffFilter = new IntentFilter();
mScreenOffFilter.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(mScreenOffReceiver, mScreenOffFilter);
// on receive method
private BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver() {
#SuppressWarnings("deprecation")
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(NOTIFY_SCREEN_OFF)) {
Intent mLockIntent = new Intent(context, LockScreenActivity.class);
mLockIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
startActivity(mLockIntent);
}
}
Disable the Lock screen
KeyguardManager mKeyguardManager = (KeyguardManager)getSystemService(Context.KEYGUARD_SERVICE);
KeyguardManager.KeyguardLock mKeyguardLock = mKeyguardManager.newKeyguardLock("CustomLockScreen");
mKeyguardLock.disableKeyguard();
Hope this could be a little help
I am having one of these mysterious android' issues (at least from my point of view). My app manages the device's camera via the camera2 api library. In my case I have two surfaces, one of them coming from an Image Reader object. Next I define my capture session and set those surfaces as targets. As you can see in the code below, I am following the typical workflows in such cases:
// Create ImageReader Surface
int max = 2;
mReader = ImageReader.newInstance(mWidth, mHeight, ImageFormat.YV12, max);
ImageReader.OnImageAvailableListener readerListener = new ImageReader.OnImageAvailableListener() {
#Override
public void onImageAvailable(ImageReader mReader) {
Image image = null;
image = mReader.acquireLatestImage();
if (image == null) {
return;
}
byte[] bytes = convertYUV420ToNV21(image);
nativeVideoFrame(bytes);
image.close();
}
};
if (OPENGL_SOURCE==2){
nativeVideoInit(mWidth, mHeight, 0, false);
}
mReader.setOnImageAvailableListener(readerListener, mBackgroundHandler);
// Create Texture Surface
texture = createTexture();
mSurfaceTexture = new SurfaceTexture(texture);
mSurfaceTexture.setOnFrameAvailableListener(this);
mSurfaceTexture.setDefaultBufferSize(imageDimension.getWidth(), imageDimension.getHeight());
mSurface = new Surface(mSurfaceTexture);
//Attach surfaces to CaptureRequest
List<Surface> outputSurfaces = new ArrayList<Surface>(2);
outputSurfaces.add(mReader.getSurface());
outputSurfaces.add(mSurface);
captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
captureRequestBuilder.addTarget(mSurface);
captureRequestBuilder.addTarget(mReader.getSurface());
//Define the capture request
cameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback(){
#Override
public void onConfigured(#NonNull CameraCaptureSession cameraCaptureSession) {
//The camera is already closed
if (null == cameraDevice) {
return;
}
// When the session is ready, we start displaying the preview.
cameraCaptureSessions = cameraCaptureSession;
updatePreview();
}
#Override
public void onConfigureFailed(#NonNull CameraCaptureSession cameraCaptureSession) {
Toast.makeText(MainActivity.this, "Configuration change", Toast.LENGTH_SHORT).show();
}
}, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
The thing is that I am not having any problem running this code on my tablet Samsung TAB A. However, when trying in my Nexus 5X or my friend's Samsung S6, the app crashes dramatically throwing this error:
08-23 11:28:51.772: E/AndroidRuntime(20315): FATAL EXCEPTION: main
08-23 11:28:51.772: E/AndroidRuntime(20315): Process: com.example.opengltest, PID: 20315
08-23 11:28:51.772: E/AndroidRuntime(20315): java.lang.IllegalArgumentException: Bad argument passed to camera service
08-23 11:28:51.772: E/AndroidRuntime(20315): at android.hardware.camera2.utils.CameraBinderDecorator.throwOnError(CameraBinderDecorator.java:114)
Doing some test, I found that the problem comes from the image reader surface. If I get rid off on this surface from the capture session's settings, the code runs seamlessly.
Why is this happening only on my Nexus 5x or Samsung S6 and not in my tablet? And how can I fix it?
Thanks,
JM
If you look at the whole system logcat, the camera service should have a
more detailed line that states why your output surface set is bad.
However, YV12 is not a format that's guaranteed to be supported, so it's probably just that. Some devices support it, some don't.
The only YUV format that's guaranteed to be supported by all devices is ImageFormat.YUV_420_888.
If you want to use YV12 when possible, you'll need to check the StreamConfigurationMap.getOutputFormats() list to see if it's listed before trying to use it. But you'll still need to fall back to YUV_420_888 on many devices, so it's simplest to just support that directly and nothing else.
Just as the title say, is it possible to programmatically interact/configure with native Camera app on Android device?
For example, I am trying to have the native camera app to take a picture without having to physically touch the capture button. I'm not wanting to use internal-timer feature in the camera app since this requires physical touch to the button as well.
So simply put, I want to know if it is possible to take a picture without physically touching the capture button.
Thanks in advance for the reply.
is it possible to programmatically interact/configure with native Camera app on Android device?
Not from an ordinary Android app.
Also, please note that there are several thousand Android device models. There are hundreds of different "native Camera app" implementations across those device models, as device manufacturers often implement their own. Your question implies that you think that there is a single "native Camera app", which is not the case.
For an individual device model, or perhaps a closely related family of devices, with a rooted device, you might be able to work something out with simulated user input. However, the myriad of camera apps means that you would need different rules for each app.
Also, if you are only concerned about your own device, you can use the uiautomator test system to control third-party apps, but that requires a connection to your development machine, as the tests are run from there.
It is possible. Just forget about "native Camera app" and use Camera/Camera2 API directly.
Some time ago I tried to make a background service taking pictire periodically, detects face and measure eyes distance to prevent my little dougter watching tab too close, but this was fail because tab camera angle was too narrow to take all her face.
I posted part of this app here (this code use depricated Camera interface. It was replaced by Camera2 interface since API21):
public void onCreate() {
super.onCreate();
mContext = getApplicationContext();
surfaceTexture = new SurfaceTexture(0);
}
public void takePictire() {
Camera cam = openFrontCamera(mContext);
if (cam != null) {
try {
cam.setPreviewTexture(surfaceTexture);
cam.startPreview();
cam.takePicture(null, null, mPicture);
} catch (Exception ex) {
Log.d(LOG_TAG, "Can't take picture!");
}
}
}
private static Camera.PictureCallback mPicture = new Camera.PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
BitmapFactory.Options bfo = new BitmapFactory.Options();
bfo.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap bitmap = BitmapFactory.decodeStream(new ByteArrayInputStream(data), null, bfo);
// Eye distance detection here and saving data
camera.stopPreview();
camera.release();
}
};
/* Check if this device has a camera */
private static Camera openFrontCamera(Context context) {
try {
boolean hasCamera = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA);
if (hasCamera) {
int cameraCount = 0;
Camera cam = null;
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
cameraCount = Camera.getNumberOfCameras();
for (int camIdx = 0; camIdx < cameraCount; camIdx++) {
Camera.getCameraInfo(camIdx, cameraInfo);
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
try {
cam = Camera.open(camIdx);
} catch (RuntimeException e) {
Log.e(LOG_TAG, "Camera failed to open: " + e.getLocalizedMessage());
}
}
}
return cam;
}
} catch (Exception ex) {
Log.d(LOG_TAG, "Can't open front camera");
}
return null;
}
Some additional info. To use this code you app should have camera permission in AndroidManifest.xml:
<uses-permission android:name="android.permission.CAMERA" />
Yes, You can capture image without any user input also in background without frame. Take a look here . Hope this help you!
I'm making music player app with simple functionality. But when I listen music on my phone with Android 6, sometimes music stops playing until I turn on display again with power button. Then next song is playing, so it seems like it's problem with loading next song. I tried to write new app just to test it out, for this purpose I used this tutorial:
https://code.tutsplus.com/tutorials/background-audio-in-android-with-mediasessioncompat--cms-27030
To this example I added ArrayList with paths to songs. In mediaPlayer onCompletionListener I increase track counter and load new song to media player.
My code:
private void initMediaPlayer() {
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.setVolume(1.0f, 1.0f);
mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mediaPlayer)
{
onTrackCompletion();
}
});
private void onTrackCompletion()
{
NextTrack();
Play();
}
private void NextTrack()
{
playlistPosition++;
if (playlistPosition == playlists.get(playlistCurrent).size){
playlistPosition = 0;
}
sendAction(ACTION_TRACK_NEXT);
if(mMediaPlayer.isPlaying()){
Pause();
}
loadSong();
Play();
}
private void loadSong()
{
String path = playlists.get(playlistCurrent).getPath(playlistPosition);
if(path == null || path == "")
{
return;
}
try
{
try
{
mMediaPlayer.setDataSource(path);
} catch( IllegalStateException e ) {
mMediaPlayer.release();
initMediaPlayer();
mMediaPlayer.setDataSource(path);
}
initMediaSessionMetadata();
} catch (IOException e) {
return;
}
try {
mMediaPlayer.prepare();
} catch (IOException e) {}
sendTrackData();
}
I don't know anymore why this doesn't work. In manifest I have WAKE_LOCK permission. I also set wake lock for Media player.
Edit:
Today I tried to move loading song into onPlayFromMediaId. I made broadcast from AutoActivity where is Media player to Main Activity and send back onPlayFromMediaId with path to song. But seems like this doesn't work either.I also find out that changing volume with buttons also wake up app.
Edit2:
I made many tests and added debug string in many places in code. And I found out that app stops at mediaplayer.prepare() until I trigger any action on phone (turn on display, volume up/down, click headset button). But I don't know how to fix this bug. I tried to use prepareAsync, but didn't help.
Unless you use foreground service, the system will kill your process and mediaplayer will stop.
below is a part from from a foreground service ( notification example).
builder.setContentTitle(aMessage) // required
.setSmallIcon(R.mipmap.ic_launcher)
.setContentText(this.getString(R.string.app_name)) // required
.setAutoCancel(false)
.setContentIntent(pendingIntent)
.setVibrate(new long[]{0L})
.setPriority(Notification.PRIORITY_HIGH);
int mId = 1489;
startForeground(mId, builder.build());
The above code is tested and working fine.