Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 586052d9 authored by The Android Open Source Project's avatar The Android Open Source Project
Browse files

Merge branch 'eclair' into eclair-release

parents 6a05a382 a47d1536
Loading
Loading
Loading
Loading
+45 −9
Original line number Diff line number Diff line
@@ -81,6 +81,7 @@ public class Camera {
    private ZoomCallback mZoomCallback;
    private ErrorCallback mErrorCallback;
    private boolean mOneShot;
    private boolean mWithBuffer;

    /**
     * Returns a new Camera object.
@@ -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);
    }

    /**
@@ -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
    {
@@ -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);
                }
+31 −64
Original line number Diff line number Diff line
@@ -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
@@ -151,8 +150,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {

        if (mBluetoothService.isEnabled())
            onBluetoothEnable();
        mSuspending = false;
        mResuming = false;
        mTargetA2dpState = -1;
    }

    @Override
@@ -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;
        }
@@ -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;
        }
@@ -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() {
@@ -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) {
@@ -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);
@@ -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;
+122 −8
Original line number Diff line number Diff line
@@ -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>
@@ -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)
@@ -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()
@@ -97,6 +109,7 @@ void JNICameraContext::release()
        env->DeleteGlobalRef(mCameraJClass);
        mCameraJClass = NULL;
    }
    clearCallbackBuffers_l(env);
    mCamera.clear();
}

@@ -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();
@@ -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)
{
@@ -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.
@@ -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)
@@ -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 },
+3 −1
Original line number Diff line number Diff line
@@ -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.
+1 −0
Original line number Diff line number Diff line
@@ -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