Unhide audio recording notification API

Introduce new methods and classes for the audio recording
  configuration update and query API.
Callback registration supports a Handler.

Bug 22876530

Change-Id: I819ad464f095d970b5d1d8a3781fcf8dbb310424
This commit is contained in:
Jean-Michel Trivi
2016-01-12 18:27:17 -08:00
parent 14176272ed
commit b919f6fd71
5 changed files with 149 additions and 55 deletions

View File

@@ -19297,6 +19297,7 @@ package android.media {
method public void adjustVolume(int, int);
method public void dispatchMediaKeyEvent(android.view.KeyEvent);
method public int generateAudioSessionId();
method public android.media.AudioRecordConfiguration[] getActiveRecordConfigurations();
method public android.media.AudioDeviceInfo[] getDevices(int);
method public int getMode();
method public java.lang.String getParameters(java.lang.String);
@@ -19319,6 +19320,7 @@ package android.media {
method public void playSoundEffect(int);
method public void playSoundEffect(int, float);
method public void registerAudioDeviceCallback(android.media.AudioDeviceCallback, android.os.Handler);
method public void registerAudioRecordingCallback(android.media.AudioManager.AudioRecordingCallback, android.os.Handler);
method public deprecated void registerMediaButtonEventReceiver(android.content.ComponentName);
method public deprecated void registerMediaButtonEventReceiver(android.app.PendingIntent);
method public deprecated void registerRemoteControlClient(android.media.RemoteControlClient);
@@ -19342,6 +19344,7 @@ package android.media {
method public void stopBluetoothSco();
method public void unloadSoundEffects();
method public void unregisterAudioDeviceCallback(android.media.AudioDeviceCallback);
method public void unregisterAudioRecordingCallback(android.media.AudioManager.AudioRecordingCallback);
method public deprecated void unregisterMediaButtonEventReceiver(android.content.ComponentName);
method public deprecated void unregisterMediaButtonEventReceiver(android.app.PendingIntent);
method public deprecated void unregisterRemoteControlClient(android.media.RemoteControlClient);
@@ -19438,6 +19441,11 @@ package android.media {
field public static final deprecated int VIBRATE_TYPE_RINGER = 0; // 0x0
}
public static abstract class AudioManager.AudioRecordingCallback {
ctor public AudioManager.AudioRecordingCallback();
method public void onRecordConfigChanged();
}
public static abstract interface AudioManager.OnAudioFocusChangeListener {
method public abstract void onAudioFocusChange(int);
}
@@ -19508,6 +19516,14 @@ package android.media {
method public abstract void onRoutingChanged(android.media.AudioRecord);
}
public class AudioRecordConfiguration implements android.os.Parcelable {
method public int describeContents();
method public int getAudioSessionId();
method public int getClientAudioSource();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.media.AudioRecordConfiguration> CREATOR;
}
public abstract interface AudioRouting {
method public abstract void addOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method public abstract android.media.AudioDeviceInfo getPreferredDevice();

View File

@@ -20623,6 +20623,7 @@ package android.media {
method public void adjustVolume(int, int);
method public void dispatchMediaKeyEvent(android.view.KeyEvent);
method public int generateAudioSessionId();
method public android.media.AudioRecordConfiguration[] getActiveRecordConfigurations();
method public android.media.AudioDeviceInfo[] getDevices(int);
method public int getMode();
method public java.lang.String getParameters(java.lang.String);
@@ -20647,6 +20648,7 @@ package android.media {
method public void playSoundEffect(int, float);
method public void registerAudioDeviceCallback(android.media.AudioDeviceCallback, android.os.Handler);
method public int registerAudioPolicy(android.media.audiopolicy.AudioPolicy);
method public void registerAudioRecordingCallback(android.media.AudioManager.AudioRecordingCallback, android.os.Handler);
method public deprecated void registerMediaButtonEventReceiver(android.content.ComponentName);
method public deprecated void registerMediaButtonEventReceiver(android.app.PendingIntent);
method public deprecated void registerRemoteControlClient(android.media.RemoteControlClient);
@@ -20673,6 +20675,7 @@ package android.media {
method public void unloadSoundEffects();
method public void unregisterAudioDeviceCallback(android.media.AudioDeviceCallback);
method public void unregisterAudioPolicyAsync(android.media.audiopolicy.AudioPolicy);
method public void unregisterAudioRecordingCallback(android.media.AudioManager.AudioRecordingCallback);
method public deprecated void unregisterMediaButtonEventReceiver(android.content.ComponentName);
method public deprecated void unregisterMediaButtonEventReceiver(android.app.PendingIntent);
method public deprecated void unregisterRemoteControlClient(android.media.RemoteControlClient);
@@ -20772,6 +20775,11 @@ package android.media {
field public static final deprecated int VIBRATE_TYPE_RINGER = 0; // 0x0
}
public static abstract class AudioManager.AudioRecordingCallback {
ctor public AudioManager.AudioRecordingCallback();
method public void onRecordConfigChanged();
}
public static abstract interface AudioManager.OnAudioFocusChangeListener {
method public abstract void onAudioFocusChange(int);
}
@@ -20845,6 +20853,14 @@ package android.media {
method public abstract void onRoutingChanged(android.media.AudioRecord);
}
public class AudioRecordConfiguration implements android.os.Parcelable {
method public int describeContents();
method public int getAudioSessionId();
method public int getClientAudioSource();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.media.AudioRecordConfiguration> CREATOR;
}
public abstract interface AudioRouting {
method public abstract void addOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method public abstract android.media.AudioDeviceInfo getPreferredDevice();

View File

@@ -19305,6 +19305,7 @@ package android.media {
method public void adjustVolume(int, int);
method public void dispatchMediaKeyEvent(android.view.KeyEvent);
method public int generateAudioSessionId();
method public android.media.AudioRecordConfiguration[] getActiveRecordConfigurations();
method public android.media.AudioDeviceInfo[] getDevices(int);
method public int getMode();
method public java.lang.String getParameters(java.lang.String);
@@ -19327,6 +19328,7 @@ package android.media {
method public void playSoundEffect(int);
method public void playSoundEffect(int, float);
method public void registerAudioDeviceCallback(android.media.AudioDeviceCallback, android.os.Handler);
method public void registerAudioRecordingCallback(android.media.AudioManager.AudioRecordingCallback, android.os.Handler);
method public deprecated void registerMediaButtonEventReceiver(android.content.ComponentName);
method public deprecated void registerMediaButtonEventReceiver(android.app.PendingIntent);
method public deprecated void registerRemoteControlClient(android.media.RemoteControlClient);
@@ -19350,6 +19352,7 @@ package android.media {
method public void stopBluetoothSco();
method public void unloadSoundEffects();
method public void unregisterAudioDeviceCallback(android.media.AudioDeviceCallback);
method public void unregisterAudioRecordingCallback(android.media.AudioManager.AudioRecordingCallback);
method public deprecated void unregisterMediaButtonEventReceiver(android.content.ComponentName);
method public deprecated void unregisterMediaButtonEventReceiver(android.app.PendingIntent);
method public deprecated void unregisterRemoteControlClient(android.media.RemoteControlClient);
@@ -19446,6 +19449,11 @@ package android.media {
field public static final deprecated int VIBRATE_TYPE_RINGER = 0; // 0x0
}
public static abstract class AudioManager.AudioRecordingCallback {
ctor public AudioManager.AudioRecordingCallback();
method public void onRecordConfigChanged();
}
public static abstract interface AudioManager.OnAudioFocusChangeListener {
method public abstract void onAudioFocusChange(int);
}
@@ -19516,6 +19524,14 @@ package android.media {
method public abstract void onRoutingChanged(android.media.AudioRecord);
}
public class AudioRecordConfiguration implements android.os.Parcelable {
method public int describeContents();
method public int getAudioSessionId();
method public int getClientAudioSource();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.media.AudioRecordConfiguration> CREATOR;
}
public abstract interface AudioRouting {
method public abstract void addOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method public abstract android.media.AudioDeviceInfo getPreferredDevice();

View File

@@ -2163,7 +2163,7 @@ public class AudioManager {
* audio service.
*/
private final ServiceEventHandlerDelegate mServiceEventHandlerDelegate =
new ServiceEventHandlerDelegate();
new ServiceEventHandlerDelegate(null);
/**
* Event types
@@ -2177,10 +2177,14 @@ public class AudioManager {
private class ServiceEventHandlerDelegate {
private final Handler mHandler;
ServiceEventHandlerDelegate() {
ServiceEventHandlerDelegate(Handler handler) {
Looper looper;
if ((looper = Looper.myLooper()) == null) {
looper = Looper.getMainLooper();
if (handler == null) {
if ((looper = Looper.myLooper()) == null) {
looper = Looper.getMainLooper();
}
} else {
looper = handler.getLooper();
}
if (looper != null) {
@@ -2201,27 +2205,9 @@ public class AudioManager {
}
break;
case MSSG_RECORDING_CONFIG_CHANGE:
// optimizing for the case of a single callback
AudioRecordingCallback singleCallback = null;
ArrayList<AudioRecordingCallback> multipleCallbacks = null;
synchronized(mRecordCallbackLock) {
if ((mRecordCallbackList != null)
&& (mRecordCallbackList.size() != 0)) {
if (mRecordCallbackList.size() == 1) {
singleCallback = mRecordCallbackList.get(0);
} else {
multipleCallbacks =
new ArrayList<AudioRecordingCallback>(
mRecordCallbackList);
}
}
}
if (singleCallback != null) {
singleCallback.onRecordConfigChanged();
} else if (multipleCallbacks != null) {
for (int i=0 ; i < multipleCallbacks.size() ; i++) {
multipleCallbacks.get(i).onRecordConfigChanged();
}
final AudioRecordingCallback cb = (AudioRecordingCallback) msg.obj;
if (cb != null) {
cb.onRecordConfigChanged();
}
break;
default:
@@ -2798,34 +2784,51 @@ public class AudioManager {
//====================================================================
// Recording configuration
/**
* @hide
* candidate for public API
* Interface for receiving update notifications about the recording configuration. Extend
* this abstract class and register it with
* {@link AudioManager#registerAudioRecordingCallback(AudioRecordingCallback, Handler)}
* to be notified.
* Use {@link AudioManager#getActiveRecordConfigurations()} to query the current configuration.
*/
public static abstract class AudioRecordingCallback {
/**
* @hide
* candidate for public API
* Called whenever the device recording configuration has changed.
*/
public void onRecordConfigChanged() {}
}
private static class AudioRecordingCallbackInfo {
final AudioRecordingCallback mCb;
final Handler mHandler;
AudioRecordingCallbackInfo(AudioRecordingCallback cb, Handler handler) {
mCb = cb;
mHandler = handler;
}
}
/**
* @hide
* candidate for public API
* @param non-null callback
* Register a callback to be notified of audio recording changes through
* {@link AudioRecordingCallback}
* @param cb non-null callback to register
* @param handler the {@link Handler} object for the thread on which to execute
* the callback. If <code>null</code>, the {@link Handler} associated with the main
* {@link Looper} will be used.
*/
public void registerAudioRecordingCallback(@NonNull AudioRecordingCallback cb) {
public void registerAudioRecordingCallback(@NonNull AudioRecordingCallback cb, Handler handler)
{
if (cb == null) {
throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument");
}
synchronized(mRecordCallbackLock) {
// lazy initialization of the list of recording callbacks
if (mRecordCallbackList == null) {
mRecordCallbackList = new ArrayList<AudioRecordingCallback>();
mRecordCallbackList = new ArrayList<AudioRecordingCallbackInfo>();
}
final int oldCbCount = mRecordCallbackList.size();
if (!mRecordCallbackList.contains(cb)) {
mRecordCallbackList.add(cb);
if (!hasRecordCallback_sync(cb)) {
mRecordCallbackList.add(new AudioRecordingCallbackInfo(cb,
new ServiceEventHandlerDelegate(handler).getHandler()));
final int newCbCount = mRecordCallbackList.size();
if ((oldCbCount == 0) && (newCbCount > 0)) {
// register binder for callbacks
@@ -2844,9 +2847,9 @@ public class AudioManager {
}
/**
* @hide
* candidate for public API
* @param non-null callback
* Unregister an audio recording callback previously registered with
* {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}.
* @param cb non-null callback to unregister
*/
public void unregisterAudioRecordingCallback(@NonNull AudioRecordingCallback cb) {
if (cb == null) {
@@ -2857,7 +2860,7 @@ public class AudioManager {
return;
}
final int oldCbCount = mRecordCallbackList.size();
if (mRecordCallbackList.remove(cb)) {
if (removeRecordCallback_sync(cb)) {
final int newCbCount = mRecordCallbackList.size();
if ((oldCbCount > 0) && (newCbCount == 0)) {
// unregister binder for callbacks
@@ -2876,8 +2879,7 @@ public class AudioManager {
}
/**
* @hide
* candidate for public API
* Returns the current active audio recording configurations of the device.
* @return a non-null array of recording configurations. An array of length 0 indicates there is
* no recording active when queried.
*/
@@ -2902,18 +2904,57 @@ public class AudioManager {
/**
* All operations on this list are sync'd on mRecordCallbackLock.
* List is lazy-initialized in {@link #registerAudioRecordingCallback(AudioRecordingCallback)}.
* List is lazy-initialized in
* {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}.
* List can be null.
*/
private List<AudioRecordingCallback> mRecordCallbackList;
private List<AudioRecordingCallbackInfo> mRecordCallbackList;
private final Object mRecordCallbackLock = new Object();
/**
* Must be called synchronized on mRecordCallbackLock
*/
private boolean hasRecordCallback_sync(@NonNull AudioRecordingCallback cb) {
if (mRecordCallbackList != null) {
for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
if (cb.equals(mRecordCallbackList.get(i).mCb)) {
return true;
}
}
}
return false;
}
/**
* Must be called synchronized on mRecordCallbackLock
*/
private boolean removeRecordCallback_sync(@NonNull AudioRecordingCallback cb) {
if (mRecordCallbackList != null) {
for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
if (cb.equals(mRecordCallbackList.get(i).mCb)) {
mRecordCallbackList.remove(i);
return true;
}
}
}
return false;
}
private final IRecordingConfigDispatcher mRecCb = new IRecordingConfigDispatcher.Stub() {
public void dispatchRecordingConfigChange() {
final Message m = mServiceEventHandlerDelegate.getHandler().obtainMessage(
MSSG_RECORDING_CONFIG_CHANGE/*what*/);
mServiceEventHandlerDelegate.getHandler().sendMessage(m);
synchronized(mRecordCallbackLock) {
if (mRecordCallbackList != null) {
for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
final AudioRecordingCallbackInfo arci = mRecordCallbackList.get(i);
if (arci.mHandler != null) {
final Message m = arci.mHandler.obtainMessage(
MSSG_RECORDING_CONFIG_CHANGE/*what*/, arci.mCb/*obj*/);
arci.mHandler.sendMessage(m);
}
}
}
}
}
};

View File

@@ -22,8 +22,9 @@ import android.os.Parcelable;
import java.util.Objects;
/**
* @hide
* Candidate for public API, see AudioManager.getActiveRecordConfiguration()
* The AudioRecordConfiguration class collects the information describing an audio recording
* session. This information is returned through the
* {@link AudioManager#getActiveRecordConfigurations()} method.
*
*/
public class AudioRecordConfiguration implements Parcelable {
@@ -41,19 +42,23 @@ public class AudioRecordConfiguration implements Parcelable {
}
/**
* @return one of AudioSource.MIC, AudioSource.VOICE_UPLINK,
* AudioSource.VOICE_DOWNLINK, AudioSource.VOICE_CALL,
* AudioSource.CAMCORDER, AudioSource.VOICE_RECOGNITION,
* AudioSource.VOICE_COMMUNICATION.
* Returns the audio source being used for the recording.
* @return one of {@link MediaRecorder.AudioSource#MIC},
* {@link MediaRecorder.AudioSource#VOICE_UPLINK},
* {@link MediaRecorder.AudioSource#VOICE_DOWNLINK},
* {@link MediaRecorder.AudioSource#VOICE_CALL},
* {@link MediaRecorder.AudioSource#CAMCORDER},
* {@link MediaRecorder.AudioSource#VOICE_RECOGNITION},
* {@link MediaRecorder.AudioSource#VOICE_COMMUNICATION}.
*/
public int getClientAudioSource() { return mClientSource; }
/**
* @return the session number of the recorder.
* Returns the session number of the recording, see {@link AudioRecord#getAudioSessionId()}.
* @return the session number.
*/
public int getAudioSessionId() { return mSessionId; }
public static final Parcelable.Creator<AudioRecordConfiguration> CREATOR
= new Parcelable.Creator<AudioRecordConfiguration>() {
/**