Loading core/java/android/hardware/Camera.java +45 −9 Original line number Diff line number Diff line Loading @@ -81,6 +81,7 @@ public class Camera { private ZoomCallback mZoomCallback; private ErrorCallback mErrorCallback; private boolean mOneShot; private boolean mWithBuffer; /** * Returns a new Camera object. Loading Loading @@ -229,9 +230,10 @@ public class Camera { public final void setPreviewCallback(PreviewCallback cb) { mPreviewCallback = cb; mOneShot = false; mWithBuffer = false; // Always use one-shot mode. We fake camera preview mode by // doing one-shot preview continuously. setHasPreviewCallback(cb != null, true); setHasPreviewCallback(cb != null, false); } /** Loading @@ -241,14 +243,48 @@ public class Camera { * @param cb A callback object that receives a copy of the preview frame. */ public final void setOneShotPreviewCallback(PreviewCallback cb) { if (cb != null) { mPreviewCallback = cb; mOneShot = true; setHasPreviewCallback(true, true); mWithBuffer = false; setHasPreviewCallback(cb != null, false); } private native final void setHasPreviewCallback(boolean installed, boolean manualBuffer); /** * Installs a callback which will get called as long as there are buffers in the * preview buffer queue, which minimizes dynamic allocation of preview buffers. * * Apps must call addCallbackBuffer to explicitly register the buffers to use, or no callbacks * will be received. addCallbackBuffer may be safely called before or after * a call to setPreviewCallbackWithBuffer with a non-null callback parameter. * * The buffer queue will be cleared upon any calls to setOneShotPreviewCallback, * setPreviewCallback, or to this method with a null callback parameter. * * @param cb A callback object that receives a copy of the preview frame. A null value will clear the queue. * @hide */ public final void setPreviewCallbackWithBuffer(PreviewCallback cb) { mPreviewCallback = cb; mOneShot = false; mWithBuffer = true; setHasPreviewCallback(cb != null, true); } private native final void setHasPreviewCallback(boolean installed, boolean oneshot); /** * Adds a pre-allocated buffer to the callback buffer queue. * Preview width and height can be determined from getPreviewSize, and bitsPerPixel can be * found from from {@link android.hardware.Camera.Parameters#getPreviewFormat()} and * {@link android.graphics.PixelFormat#getPixelFormatInfo(int, PixelFormat)} * * Alternatively, a buffer from a previous callback may be passed in or used * to determine the size of new preview frame buffers. * * @param callbackBuffer The buffer to register. Size should be width * height * bitsPerPixel / 8. * @hide */ public native final void addCallbackBuffer(byte[] callbackBuffer); private class EventHandler extends Handler { Loading Loading @@ -288,11 +324,11 @@ public class Camera { // in case the app calls setPreviewCallback from // the callback function mPreviewCallback = null; } else { } else if (!mWithBuffer) { // We're faking the camera preview mode to prevent // the app from being flooded with preview frames. // Set to oneshot mode again. setHasPreviewCallback(true, true); setHasPreviewCallback(true, false); } cb.onPreviewFrame((byte[])msg.obj, mCamera); } Loading core/java/android/server/BluetoothA2dpService.java +31 −64 Original line number Diff line number Diff line Loading @@ -72,8 +72,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { private final AudioManager mAudioManager; private final BluetoothService mBluetoothService; private final BluetoothAdapter mAdapter; private boolean mSuspending; private boolean mResuming; private int mTargetA2dpState; private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override Loading Loading @@ -151,8 +150,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { if (mBluetoothService.isEnabled()) onBluetoothEnable(); mSuspending = false; mResuming = false; mTargetA2dpState = -1; } @Override Loading Loading @@ -341,10 +339,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { public synchronized boolean suspendSink(BluetoothDevice device) { mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); if (DBG) log("suspendSink(" + device + "), mSuspending: "+mSuspending+", mResuming: "+mResuming); if (mSuspending) { return true; } if (DBG) log("suspendSink(" + device + "), mTargetA2dpState: "+mTargetA2dpState); if (device == null || mAudioDevices == null) { return false; } Loading @@ -353,28 +348,15 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { if (path == null || state == null) { return false; } switch (state.intValue()) { case BluetoothA2dp.STATE_CONNECTED: if (mResuming) { mSuspending = true; } return true; case BluetoothA2dp.STATE_PLAYING: mAudioManager.setParameters("A2dpSuspended=true"); mSuspending = suspendSinkNative(path); return mSuspending; default: return false; } mTargetA2dpState = BluetoothA2dp.STATE_CONNECTED; return checkSinkSuspendState(state.intValue()); } public synchronized boolean resumeSink(BluetoothDevice device) { mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); if (DBG) log("resumeSink(" + device + "), mResuming: "+mResuming+", mSuspending: "+mSuspending); if (mResuming) { return true; } if (DBG) log("resumeSink(" + device + "), mTargetA2dpState: "+mTargetA2dpState); if (device == null || mAudioDevices == null) { return false; } Loading @@ -383,19 +365,8 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { if (path == null || state == null) { return false; } switch (state.intValue()) { case BluetoothA2dp.STATE_PLAYING: if (mSuspending) { mResuming = true; } return true; case BluetoothA2dp.STATE_CONNECTED: mResuming = resumeSinkNative(path); mAudioManager.setParameters("A2dpSuspended=false"); return mResuming; default: return false; } mTargetA2dpState = BluetoothA2dp.STATE_PLAYING; return checkSinkSuspendState(state.intValue()); } public synchronized BluetoothDevice[] getConnectedSinks() { Loading Loading @@ -458,10 +429,6 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { } private void handleSinkStateChange(BluetoothDevice device, int prevState, int state) { if (state == BluetoothA2dp.STATE_DISCONNECTED) { mSuspending = false; mResuming = false; } if (state != prevState) { if (state == BluetoothA2dp.STATE_DISCONNECTED || state == BluetoothA2dp.STATE_DISCONNECTING) { Loading @@ -477,28 +444,11 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { } mAudioDevices.put(device, state); if (state == BluetoothA2dp.STATE_CONNECTED && prevState == BluetoothA2dp.STATE_PLAYING) { if (DBG) log("handleSinkStateChange() STATE_PLAYING -> STATE_CONNECTED: mSuspending: " +mSuspending+", mResuming: "+mResuming); if (mSuspending) { mSuspending = false; if (mResuming) { mResuming = false; resumeSink(device); } } } if (state == BluetoothA2dp.STATE_PLAYING && prevState == BluetoothA2dp.STATE_CONNECTED) { if (DBG) log("handleSinkStateChange() STATE_CONNECTED -> STATE_PLAYING: mSuspending: " +mSuspending+", mResuming: "+mResuming); checkSinkSuspendState(state); mTargetA2dpState = -1; if (mResuming) { mResuming = false; if (mSuspending) { mSuspending = false; suspendSink(device); } } if (state == BluetoothA2dp.STATE_CONNECTING) { mAudioManager.setParameters("A2dpSuspended=false"); } Intent intent = new Intent(BluetoothA2dp.ACTION_SINK_STATE_CHANGED); intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); Loading Loading @@ -527,6 +477,23 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { return sinks; } private boolean checkSinkSuspendState(int state) { boolean result = true; if (state != mTargetA2dpState) { if (state == BluetoothA2dp.STATE_PLAYING && mTargetA2dpState == BluetoothA2dp.STATE_CONNECTED) { mAudioManager.setParameters("A2dpSuspended=true"); } else if (state == BluetoothA2dp.STATE_CONNECTED && mTargetA2dpState == BluetoothA2dp.STATE_PLAYING) { mAudioManager.setParameters("A2dpSuspended=false"); } else { result = false; } } return result; } @Override protected synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (mAudioDevices.isEmpty()) return; Loading core/jni/android_hardware_Camera.cpp +122 −8 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ #include "JNIHelp.h" #include "android_runtime/AndroidRuntime.h" #include <utils/Vector.h> #include <ui/Surface.h> #include <ui/Camera.h> #include <binder/IMemory.h> Loading @@ -47,16 +49,23 @@ public: virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2); virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr); virtual void postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr); void addCallbackBuffer(JNIEnv *env, jbyteArray cbb); void setCallbackMode(JNIEnv *env, bool installed, bool manualMode); sp<Camera> getCamera() { Mutex::Autolock _l(mLock); return mCamera; } void release(); private: void copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int msgType); void clearCallbackBuffers_l(JNIEnv *env); jobject mCameraJObjectWeak; // weak reference to java object jclass mCameraJClass; // strong reference to java class sp<Camera> mCamera; // strong reference to native object Mutex mLock; Vector<jbyteArray> mCallbackBuffers; // Global reference application managed byte[] bool mManualBufferMode; // Whether to use application managed buffers. bool mManualCameraCallbackSet; // Whether the callback has been set, used to reduce unnecessary calls to set the callback. }; sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, JNICameraContext** pContext) Loading @@ -81,6 +90,9 @@ JNICameraContext::JNICameraContext(JNIEnv* env, jobject weak_this, jclass clazz, mCameraJObjectWeak = env->NewGlobalRef(weak_this); mCameraJClass = (jclass)env->NewGlobalRef(clazz); mCamera = camera; mManualBufferMode = false; mManualCameraCallbackSet = false; } void JNICameraContext::release() Loading @@ -97,6 +109,7 @@ void JNICameraContext::release() env->DeleteGlobalRef(mCameraJClass); mCameraJClass = NULL; } clearCallbackBuffers_l(env); mCamera.clear(); } Loading Loading @@ -129,7 +142,42 @@ void JNICameraContext::copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int if (heapBase != NULL) { const jbyte* data = reinterpret_cast<const jbyte*>(heapBase + offset); if (!mManualBufferMode) { LOGV("Allocating callback buffer"); obj = env->NewByteArray(size); } else { // Vector access should be protected by lock in postData() if(!mCallbackBuffers.isEmpty()) { LOGV("Using callback buffer from queue of length %d", mCallbackBuffers.size()); jbyteArray globalBuffer = mCallbackBuffers.itemAt(0); mCallbackBuffers.removeAt(0); obj = (jbyteArray)env->NewLocalRef(globalBuffer); env->DeleteGlobalRef(globalBuffer); if (obj != NULL) { jsize bufferLength = env->GetArrayLength(obj); if ((int)bufferLength < (int)size) { LOGE("Manually set buffer was too small! Expected %d bytes, but got %d!", size, bufferLength); env->DeleteLocalRef(obj); return; } } } if(mCallbackBuffers.isEmpty()) { LOGW("Out of buffers, clearing callback!"); mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP); mManualCameraCallbackSet = false; if (obj == NULL) { return; } } } if (obj == NULL) { LOGE("Couldn't allocate byte array for JPEG data"); env->ExceptionClear(); Loading Loading @@ -184,6 +232,62 @@ void JNICameraContext::postDataTimestamp(nsecs_t timestamp, int32_t msgType, con postData(msgType, dataPtr); } void JNICameraContext::setCallbackMode(JNIEnv *env, bool installed, bool manualMode) { Mutex::Autolock _l(mLock); mManualBufferMode = manualMode; mManualCameraCallbackSet = false; // In order to limit the over usage of binder threads, all non-manual buffer // callbacks use FRAME_CALLBACK_FLAG_BARCODE_SCANNER mode now. // // Continuous callbacks will have the callback re-registered from handleMessage. // Manual buffer mode will operate as fast as possible, relying on the finite supply // of buffers for throttling. if (!installed) { mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP); clearCallbackBuffers_l(env); } else if (mManualBufferMode) { if (!mCallbackBuffers.isEmpty()) { mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_CAMERA); mManualCameraCallbackSet = true; } } else { mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_BARCODE_SCANNER); clearCallbackBuffers_l(env); } } void JNICameraContext::addCallbackBuffer(JNIEnv *env, jbyteArray cbb) { if (cbb != NULL) { Mutex::Autolock _l(mLock); jbyteArray callbackBuffer = (jbyteArray)env->NewGlobalRef(cbb); mCallbackBuffers.push(cbb); LOGV("Adding callback buffer to queue, %d total", mCallbackBuffers.size()); // We want to make sure the camera knows we're ready for the next frame. // This may have come unset had we not had a callbackbuffer ready for it last time. if (mManualBufferMode && !mManualCameraCallbackSet) { mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_CAMERA); mManualCameraCallbackSet = true; } } else { LOGE("Null byte array!"); } } void JNICameraContext::clearCallbackBuffers_l(JNIEnv *env) { LOGV("Clearing callback buffers, %d remained", mCallbackBuffers.size()); while(!mCallbackBuffers.isEmpty()) { env->DeleteGlobalRef(mCallbackBuffers.top()); mCallbackBuffers.pop(); } } // connect to camera service static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobject weak_this) { Loading Loading @@ -297,8 +401,9 @@ static bool android_hardware_Camera_previewEnabled(JNIEnv *env, jobject thiz) return c->previewEnabled(); } static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject thiz, jboolean installed, jboolean oneshot) static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject thiz, jboolean installed, jboolean manualBuffer) { LOGV("setHasPreviewCallback: installed:%d, manualBuffer:%d", (int)installed, (int)manualBuffer); // Important: Only install preview_callback if the Java code has called // setPreviewCallback() with a non-null value, otherwise we'd pay to memcpy // each preview frame for nothing. Loading @@ -306,13 +411,19 @@ static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject t sp<Camera> camera = get_native_camera(env, thiz, &context); if (camera == 0) return; int callback_flag; if (installed) { callback_flag = oneshot ? FRAME_CALLBACK_FLAG_BARCODE_SCANNER : FRAME_CALLBACK_FLAG_CAMERA; } else { callback_flag = FRAME_CALLBACK_FLAG_NOOP; // setCallbackMode will take care of setting the context flags and calling // camera->setPreviewCallbackFlags within a mutex for us. context->setCallbackMode(env, installed, manualBuffer); } static void android_hardware_Camera_addCallbackBuffer(JNIEnv *env, jobject thiz, jbyteArray bytes) { LOGV("addCallbackBuffer"); JNICameraContext* context = reinterpret_cast<JNICameraContext*>(env->GetIntField(thiz, fields.context)); if (context != NULL) { context->addCallbackBuffer(env, bytes); } camera->setPreviewCallbackFlags(callback_flag); } static void android_hardware_Camera_autoFocus(JNIEnv *env, jobject thiz) Loading Loading @@ -459,6 +570,9 @@ static JNINativeMethod camMethods[] = { { "setHasPreviewCallback", "(ZZ)V", (void *)android_hardware_Camera_setHasPreviewCallback }, { "addCallbackBuffer", "([B)V", (void *)android_hardware_Camera_addCallbackBuffer }, { "native_autoFocus", "()V", (void *)android_hardware_Camera_autoFocus }, Loading core/res/res/values/config.xml +3 −1 Original line number Diff line number Diff line Loading @@ -71,7 +71,9 @@ the slider can be opened (for example, in a pocket or purse). --> <bool name="config_bypass_keyguard_if_slider_open">true</bool> <!-- Flag indicating whether the device supports automatic brightness mode in hardware. --> <!-- Flag indicating whether the device supports automatic brightness mode in hardware. WARNING - DO NOT USE THIS FEATURE Hardware auto brightness support is deprecated and will be removed in the next release. --> <bool name="config_hardware_automatic_brightness_available">false</bool> <!-- Flag indicating whether the we should enable the automatic brightness in Settings. Loading include/media/AudioSystem.h +1 −0 Original line number Diff line number Diff line Loading @@ -220,6 +220,7 @@ public: static status_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount, size_t* buffSize); static status_t setVoiceVolume(float volume); // // AudioPolicyService interface Loading Loading
core/java/android/hardware/Camera.java +45 −9 Original line number Diff line number Diff line Loading @@ -81,6 +81,7 @@ public class Camera { private ZoomCallback mZoomCallback; private ErrorCallback mErrorCallback; private boolean mOneShot; private boolean mWithBuffer; /** * Returns a new Camera object. Loading Loading @@ -229,9 +230,10 @@ public class Camera { public final void setPreviewCallback(PreviewCallback cb) { mPreviewCallback = cb; mOneShot = false; mWithBuffer = false; // Always use one-shot mode. We fake camera preview mode by // doing one-shot preview continuously. setHasPreviewCallback(cb != null, true); setHasPreviewCallback(cb != null, false); } /** Loading @@ -241,14 +243,48 @@ public class Camera { * @param cb A callback object that receives a copy of the preview frame. */ public final void setOneShotPreviewCallback(PreviewCallback cb) { if (cb != null) { mPreviewCallback = cb; mOneShot = true; setHasPreviewCallback(true, true); mWithBuffer = false; setHasPreviewCallback(cb != null, false); } private native final void setHasPreviewCallback(boolean installed, boolean manualBuffer); /** * Installs a callback which will get called as long as there are buffers in the * preview buffer queue, which minimizes dynamic allocation of preview buffers. * * Apps must call addCallbackBuffer to explicitly register the buffers to use, or no callbacks * will be received. addCallbackBuffer may be safely called before or after * a call to setPreviewCallbackWithBuffer with a non-null callback parameter. * * The buffer queue will be cleared upon any calls to setOneShotPreviewCallback, * setPreviewCallback, or to this method with a null callback parameter. * * @param cb A callback object that receives a copy of the preview frame. A null value will clear the queue. * @hide */ public final void setPreviewCallbackWithBuffer(PreviewCallback cb) { mPreviewCallback = cb; mOneShot = false; mWithBuffer = true; setHasPreviewCallback(cb != null, true); } private native final void setHasPreviewCallback(boolean installed, boolean oneshot); /** * Adds a pre-allocated buffer to the callback buffer queue. * Preview width and height can be determined from getPreviewSize, and bitsPerPixel can be * found from from {@link android.hardware.Camera.Parameters#getPreviewFormat()} and * {@link android.graphics.PixelFormat#getPixelFormatInfo(int, PixelFormat)} * * Alternatively, a buffer from a previous callback may be passed in or used * to determine the size of new preview frame buffers. * * @param callbackBuffer The buffer to register. Size should be width * height * bitsPerPixel / 8. * @hide */ public native final void addCallbackBuffer(byte[] callbackBuffer); private class EventHandler extends Handler { Loading Loading @@ -288,11 +324,11 @@ public class Camera { // in case the app calls setPreviewCallback from // the callback function mPreviewCallback = null; } else { } else if (!mWithBuffer) { // We're faking the camera preview mode to prevent // the app from being flooded with preview frames. // Set to oneshot mode again. setHasPreviewCallback(true, true); setHasPreviewCallback(true, false); } cb.onPreviewFrame((byte[])msg.obj, mCamera); } Loading
core/java/android/server/BluetoothA2dpService.java +31 −64 Original line number Diff line number Diff line Loading @@ -72,8 +72,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { private final AudioManager mAudioManager; private final BluetoothService mBluetoothService; private final BluetoothAdapter mAdapter; private boolean mSuspending; private boolean mResuming; private int mTargetA2dpState; private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override Loading Loading @@ -151,8 +150,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { if (mBluetoothService.isEnabled()) onBluetoothEnable(); mSuspending = false; mResuming = false; mTargetA2dpState = -1; } @Override Loading Loading @@ -341,10 +339,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { public synchronized boolean suspendSink(BluetoothDevice device) { mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); if (DBG) log("suspendSink(" + device + "), mSuspending: "+mSuspending+", mResuming: "+mResuming); if (mSuspending) { return true; } if (DBG) log("suspendSink(" + device + "), mTargetA2dpState: "+mTargetA2dpState); if (device == null || mAudioDevices == null) { return false; } Loading @@ -353,28 +348,15 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { if (path == null || state == null) { return false; } switch (state.intValue()) { case BluetoothA2dp.STATE_CONNECTED: if (mResuming) { mSuspending = true; } return true; case BluetoothA2dp.STATE_PLAYING: mAudioManager.setParameters("A2dpSuspended=true"); mSuspending = suspendSinkNative(path); return mSuspending; default: return false; } mTargetA2dpState = BluetoothA2dp.STATE_CONNECTED; return checkSinkSuspendState(state.intValue()); } public synchronized boolean resumeSink(BluetoothDevice device) { mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); if (DBG) log("resumeSink(" + device + "), mResuming: "+mResuming+", mSuspending: "+mSuspending); if (mResuming) { return true; } if (DBG) log("resumeSink(" + device + "), mTargetA2dpState: "+mTargetA2dpState); if (device == null || mAudioDevices == null) { return false; } Loading @@ -383,19 +365,8 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { if (path == null || state == null) { return false; } switch (state.intValue()) { case BluetoothA2dp.STATE_PLAYING: if (mSuspending) { mResuming = true; } return true; case BluetoothA2dp.STATE_CONNECTED: mResuming = resumeSinkNative(path); mAudioManager.setParameters("A2dpSuspended=false"); return mResuming; default: return false; } mTargetA2dpState = BluetoothA2dp.STATE_PLAYING; return checkSinkSuspendState(state.intValue()); } public synchronized BluetoothDevice[] getConnectedSinks() { Loading Loading @@ -458,10 +429,6 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { } private void handleSinkStateChange(BluetoothDevice device, int prevState, int state) { if (state == BluetoothA2dp.STATE_DISCONNECTED) { mSuspending = false; mResuming = false; } if (state != prevState) { if (state == BluetoothA2dp.STATE_DISCONNECTED || state == BluetoothA2dp.STATE_DISCONNECTING) { Loading @@ -477,28 +444,11 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { } mAudioDevices.put(device, state); if (state == BluetoothA2dp.STATE_CONNECTED && prevState == BluetoothA2dp.STATE_PLAYING) { if (DBG) log("handleSinkStateChange() STATE_PLAYING -> STATE_CONNECTED: mSuspending: " +mSuspending+", mResuming: "+mResuming); if (mSuspending) { mSuspending = false; if (mResuming) { mResuming = false; resumeSink(device); } } } if (state == BluetoothA2dp.STATE_PLAYING && prevState == BluetoothA2dp.STATE_CONNECTED) { if (DBG) log("handleSinkStateChange() STATE_CONNECTED -> STATE_PLAYING: mSuspending: " +mSuspending+", mResuming: "+mResuming); checkSinkSuspendState(state); mTargetA2dpState = -1; if (mResuming) { mResuming = false; if (mSuspending) { mSuspending = false; suspendSink(device); } } if (state == BluetoothA2dp.STATE_CONNECTING) { mAudioManager.setParameters("A2dpSuspended=false"); } Intent intent = new Intent(BluetoothA2dp.ACTION_SINK_STATE_CHANGED); intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); Loading Loading @@ -527,6 +477,23 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { return sinks; } private boolean checkSinkSuspendState(int state) { boolean result = true; if (state != mTargetA2dpState) { if (state == BluetoothA2dp.STATE_PLAYING && mTargetA2dpState == BluetoothA2dp.STATE_CONNECTED) { mAudioManager.setParameters("A2dpSuspended=true"); } else if (state == BluetoothA2dp.STATE_CONNECTED && mTargetA2dpState == BluetoothA2dp.STATE_PLAYING) { mAudioManager.setParameters("A2dpSuspended=false"); } else { result = false; } } return result; } @Override protected synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (mAudioDevices.isEmpty()) return; Loading
core/jni/android_hardware_Camera.cpp +122 −8 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ #include "JNIHelp.h" #include "android_runtime/AndroidRuntime.h" #include <utils/Vector.h> #include <ui/Surface.h> #include <ui/Camera.h> #include <binder/IMemory.h> Loading @@ -47,16 +49,23 @@ public: virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2); virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr); virtual void postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr); void addCallbackBuffer(JNIEnv *env, jbyteArray cbb); void setCallbackMode(JNIEnv *env, bool installed, bool manualMode); sp<Camera> getCamera() { Mutex::Autolock _l(mLock); return mCamera; } void release(); private: void copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int msgType); void clearCallbackBuffers_l(JNIEnv *env); jobject mCameraJObjectWeak; // weak reference to java object jclass mCameraJClass; // strong reference to java class sp<Camera> mCamera; // strong reference to native object Mutex mLock; Vector<jbyteArray> mCallbackBuffers; // Global reference application managed byte[] bool mManualBufferMode; // Whether to use application managed buffers. bool mManualCameraCallbackSet; // Whether the callback has been set, used to reduce unnecessary calls to set the callback. }; sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, JNICameraContext** pContext) Loading @@ -81,6 +90,9 @@ JNICameraContext::JNICameraContext(JNIEnv* env, jobject weak_this, jclass clazz, mCameraJObjectWeak = env->NewGlobalRef(weak_this); mCameraJClass = (jclass)env->NewGlobalRef(clazz); mCamera = camera; mManualBufferMode = false; mManualCameraCallbackSet = false; } void JNICameraContext::release() Loading @@ -97,6 +109,7 @@ void JNICameraContext::release() env->DeleteGlobalRef(mCameraJClass); mCameraJClass = NULL; } clearCallbackBuffers_l(env); mCamera.clear(); } Loading Loading @@ -129,7 +142,42 @@ void JNICameraContext::copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int if (heapBase != NULL) { const jbyte* data = reinterpret_cast<const jbyte*>(heapBase + offset); if (!mManualBufferMode) { LOGV("Allocating callback buffer"); obj = env->NewByteArray(size); } else { // Vector access should be protected by lock in postData() if(!mCallbackBuffers.isEmpty()) { LOGV("Using callback buffer from queue of length %d", mCallbackBuffers.size()); jbyteArray globalBuffer = mCallbackBuffers.itemAt(0); mCallbackBuffers.removeAt(0); obj = (jbyteArray)env->NewLocalRef(globalBuffer); env->DeleteGlobalRef(globalBuffer); if (obj != NULL) { jsize bufferLength = env->GetArrayLength(obj); if ((int)bufferLength < (int)size) { LOGE("Manually set buffer was too small! Expected %d bytes, but got %d!", size, bufferLength); env->DeleteLocalRef(obj); return; } } } if(mCallbackBuffers.isEmpty()) { LOGW("Out of buffers, clearing callback!"); mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP); mManualCameraCallbackSet = false; if (obj == NULL) { return; } } } if (obj == NULL) { LOGE("Couldn't allocate byte array for JPEG data"); env->ExceptionClear(); Loading Loading @@ -184,6 +232,62 @@ void JNICameraContext::postDataTimestamp(nsecs_t timestamp, int32_t msgType, con postData(msgType, dataPtr); } void JNICameraContext::setCallbackMode(JNIEnv *env, bool installed, bool manualMode) { Mutex::Autolock _l(mLock); mManualBufferMode = manualMode; mManualCameraCallbackSet = false; // In order to limit the over usage of binder threads, all non-manual buffer // callbacks use FRAME_CALLBACK_FLAG_BARCODE_SCANNER mode now. // // Continuous callbacks will have the callback re-registered from handleMessage. // Manual buffer mode will operate as fast as possible, relying on the finite supply // of buffers for throttling. if (!installed) { mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP); clearCallbackBuffers_l(env); } else if (mManualBufferMode) { if (!mCallbackBuffers.isEmpty()) { mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_CAMERA); mManualCameraCallbackSet = true; } } else { mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_BARCODE_SCANNER); clearCallbackBuffers_l(env); } } void JNICameraContext::addCallbackBuffer(JNIEnv *env, jbyteArray cbb) { if (cbb != NULL) { Mutex::Autolock _l(mLock); jbyteArray callbackBuffer = (jbyteArray)env->NewGlobalRef(cbb); mCallbackBuffers.push(cbb); LOGV("Adding callback buffer to queue, %d total", mCallbackBuffers.size()); // We want to make sure the camera knows we're ready for the next frame. // This may have come unset had we not had a callbackbuffer ready for it last time. if (mManualBufferMode && !mManualCameraCallbackSet) { mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_CAMERA); mManualCameraCallbackSet = true; } } else { LOGE("Null byte array!"); } } void JNICameraContext::clearCallbackBuffers_l(JNIEnv *env) { LOGV("Clearing callback buffers, %d remained", mCallbackBuffers.size()); while(!mCallbackBuffers.isEmpty()) { env->DeleteGlobalRef(mCallbackBuffers.top()); mCallbackBuffers.pop(); } } // connect to camera service static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobject weak_this) { Loading Loading @@ -297,8 +401,9 @@ static bool android_hardware_Camera_previewEnabled(JNIEnv *env, jobject thiz) return c->previewEnabled(); } static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject thiz, jboolean installed, jboolean oneshot) static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject thiz, jboolean installed, jboolean manualBuffer) { LOGV("setHasPreviewCallback: installed:%d, manualBuffer:%d", (int)installed, (int)manualBuffer); // Important: Only install preview_callback if the Java code has called // setPreviewCallback() with a non-null value, otherwise we'd pay to memcpy // each preview frame for nothing. Loading @@ -306,13 +411,19 @@ static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject t sp<Camera> camera = get_native_camera(env, thiz, &context); if (camera == 0) return; int callback_flag; if (installed) { callback_flag = oneshot ? FRAME_CALLBACK_FLAG_BARCODE_SCANNER : FRAME_CALLBACK_FLAG_CAMERA; } else { callback_flag = FRAME_CALLBACK_FLAG_NOOP; // setCallbackMode will take care of setting the context flags and calling // camera->setPreviewCallbackFlags within a mutex for us. context->setCallbackMode(env, installed, manualBuffer); } static void android_hardware_Camera_addCallbackBuffer(JNIEnv *env, jobject thiz, jbyteArray bytes) { LOGV("addCallbackBuffer"); JNICameraContext* context = reinterpret_cast<JNICameraContext*>(env->GetIntField(thiz, fields.context)); if (context != NULL) { context->addCallbackBuffer(env, bytes); } camera->setPreviewCallbackFlags(callback_flag); } static void android_hardware_Camera_autoFocus(JNIEnv *env, jobject thiz) Loading Loading @@ -459,6 +570,9 @@ static JNINativeMethod camMethods[] = { { "setHasPreviewCallback", "(ZZ)V", (void *)android_hardware_Camera_setHasPreviewCallback }, { "addCallbackBuffer", "([B)V", (void *)android_hardware_Camera_addCallbackBuffer }, { "native_autoFocus", "()V", (void *)android_hardware_Camera_autoFocus }, Loading
core/res/res/values/config.xml +3 −1 Original line number Diff line number Diff line Loading @@ -71,7 +71,9 @@ the slider can be opened (for example, in a pocket or purse). --> <bool name="config_bypass_keyguard_if_slider_open">true</bool> <!-- Flag indicating whether the device supports automatic brightness mode in hardware. --> <!-- Flag indicating whether the device supports automatic brightness mode in hardware. WARNING - DO NOT USE THIS FEATURE Hardware auto brightness support is deprecated and will be removed in the next release. --> <bool name="config_hardware_automatic_brightness_available">false</bool> <!-- Flag indicating whether the we should enable the automatic brightness in Settings. Loading
include/media/AudioSystem.h +1 −0 Original line number Diff line number Diff line Loading @@ -220,6 +220,7 @@ public: static status_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount, size_t* buffSize); static status_t setVoiceVolume(float volume); // // AudioPolicyService interface Loading