am 1a89c532: Merge "New media button API." into jb-mr2-dev

* commit '1a89c5324badd10dac142a5a0c40a203503db65f':
  New media button API.
This commit is contained in:
Dianne Hackborn
2013-03-22 23:18:15 +00:00
committed by Android Git Automerger
5 changed files with 226 additions and 22 deletions

View File

@ -10956,6 +10956,7 @@ package android.media {
method public void playSoundEffect(int);
method public void playSoundEffect(int, float);
method public void registerMediaButtonEventReceiver(android.content.ComponentName);
method public void registerMediaButtonEventReceiver(android.app.PendingIntent);
method public void registerRemoteControlClient(android.media.RemoteControlClient);
method public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, int, int);
method public deprecated void setBluetoothA2dpOn(boolean);
@ -10976,6 +10977,7 @@ package android.media {
method public void stopBluetoothSco();
method public void unloadSoundEffects();
method public void unregisterMediaButtonEventReceiver(android.content.ComponentName);
method public void unregisterMediaButtonEventReceiver(android.app.PendingIntent);
method public void unregisterRemoteControlClient(android.media.RemoteControlClient);
field public static final java.lang.String ACTION_AUDIO_BECOMING_NOISY = "android.media.AUDIO_BECOMING_NOISY";
field public static final deprecated java.lang.String ACTION_SCO_AUDIO_STATE_CHANGED = "android.media.SCO_AUDIO_STATE_CHANGED";
@ -26132,6 +26134,8 @@ package android.view {
method public void addOnPreDrawListener(android.view.ViewTreeObserver.OnPreDrawListener);
method public void addOnScrollChangedListener(android.view.ViewTreeObserver.OnScrollChangedListener);
method public void addOnTouchModeChangeListener(android.view.ViewTreeObserver.OnTouchModeChangeListener);
method public void addOnWindowAttachListener(android.view.ViewTreeObserver.OnWindowAttachListener);
method public void addOnWindowFocusChangeListener(android.view.ViewTreeObserver.OnWindowFocusChangeListener);
method public final void dispatchOnDraw();
method public final void dispatchOnGlobalLayout();
method public final boolean dispatchOnPreDraw();
@ -26143,6 +26147,8 @@ package android.view {
method public void removeOnPreDrawListener(android.view.ViewTreeObserver.OnPreDrawListener);
method public void removeOnScrollChangedListener(android.view.ViewTreeObserver.OnScrollChangedListener);
method public void removeOnTouchModeChangeListener(android.view.ViewTreeObserver.OnTouchModeChangeListener);
method public void removeOnWindowAttachListener(android.view.ViewTreeObserver.OnWindowAttachListener);
method public void removeOnWindowFocusChangeListener(android.view.ViewTreeObserver.OnWindowFocusChangeListener);
}
public static abstract interface ViewTreeObserver.OnDrawListener {
@ -26169,6 +26175,15 @@ package android.view {
method public abstract void onTouchModeChanged(boolean);
}
public static abstract interface ViewTreeObserver.OnWindowAttachListener {
method public abstract void onWindowAttached();
method public abstract void onWindowDetached();
}
public static abstract interface ViewTreeObserver.OnWindowFocusChangeListener {
method public abstract void onWindowFocusChanged(boolean);
}
public abstract class Window {
ctor public Window(android.content.Context);
method public abstract void addContentView(android.view.View, android.view.ViewGroup.LayoutParams);

View File

@ -1233,6 +1233,7 @@ public final class ViewRootImpl implements ViewParent,
host.setLayoutDirection(mLastConfiguration.getLayoutDirection());
}
host.dispatchAttachedToWindow(attachInfo, 0);
attachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true);
mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
host.fitSystemWindows(mFitSystemWindowsInsets);
//Log.i(TAG, "Screen on initialized: " + attachInfo.mKeepScreenOn);
@ -2827,6 +2828,7 @@ public final class ViewRootImpl implements ViewParent,
mAttachInfo.mHardwareRenderer.isEnabled()) {
mAttachInfo.mHardwareRenderer.validate();
}
mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
mView.dispatchDetachedFromWindow();
}
@ -3127,6 +3129,7 @@ public final class ViewRootImpl implements ViewParent,
}
mAttachInfo.mKeyDispatchState.reset();
mView.dispatchWindowFocusChanged(hasWindowFocus);
mAttachInfo.mTreeObserver.dispatchOnWindowFocusChange(hasWindowFocus);
}
// Note: must be done after the focus change callbacks,

View File

@ -33,6 +33,8 @@ import java.util.concurrent.CopyOnWriteArrayList;
*/
public final class ViewTreeObserver {
// Recursive listeners use CopyOnWriteArrayList
private CopyOnWriteArrayList<OnWindowFocusChangeListener> mOnWindowFocusListeners;
private CopyOnWriteArrayList<OnWindowAttachListener> mOnWindowAttachListeners;
private CopyOnWriteArrayList<OnGlobalFocusChangeListener> mOnGlobalFocusListeners;
private CopyOnWriteArrayList<OnTouchModeChangeListener> mOnTouchModeChangeListeners;
@ -48,6 +50,36 @@ public final class ViewTreeObserver {
private boolean mAlive = true;
/**
* Interface definition for a callback to be invoked when the view hierarchy is
* attached to and detached from its window.
*/
public interface OnWindowAttachListener {
/**
* Callback method to be invoked when the view hierarchy is attached to a window
*/
public void onWindowAttached();
/**
* Callback method to be invoked when the view hierarchy is detached from a window
*/
public void onWindowDetached();
}
/**
* Interface definition for a callback to be invoked when the view hierarchy's window
* focus state changes.
*/
public interface OnWindowFocusChangeListener {
/**
* Callback method to be invoked when the window focus changes in the view tree.
*
* @param hasFocus Set to true if the window is gaining focus, false if it is
* losing focus.
*/
public void onWindowFocusChanged(boolean hasFocus);
}
/**
* Interface definition for a callback to be invoked when the focus state within
* the view tree changes.
@ -272,6 +304,22 @@ public final class ViewTreeObserver {
* @param observer The ViewTreeObserver whose listeners must be added to this observer
*/
void merge(ViewTreeObserver observer) {
if (observer.mOnWindowAttachListeners != null) {
if (mOnWindowAttachListeners != null) {
mOnWindowAttachListeners.addAll(observer.mOnWindowAttachListeners);
} else {
mOnWindowAttachListeners = observer.mOnWindowAttachListeners;
}
}
if (observer.mOnWindowFocusListeners != null) {
if (mOnWindowFocusListeners != null) {
mOnWindowFocusListeners.addAll(observer.mOnWindowFocusListeners);
} else {
mOnWindowFocusListeners = observer.mOnWindowFocusListeners;
}
}
if (observer.mOnGlobalFocusListeners != null) {
if (mOnGlobalFocusListeners != null) {
mOnGlobalFocusListeners.addAll(observer.mOnGlobalFocusListeners);
@ -323,6 +371,76 @@ public final class ViewTreeObserver {
observer.kill();
}
/**
* Register a callback to be invoked when the view hierarchy is attached to a window.
*
* @param listener The callback to add
*
* @throws IllegalStateException If {@link #isAlive()} returns false
*/
public void addOnWindowAttachListener(OnWindowAttachListener listener) {
checkIsAlive();
if (mOnWindowAttachListeners == null) {
mOnWindowAttachListeners
= new CopyOnWriteArrayList<OnWindowAttachListener>();
}
mOnWindowAttachListeners.add(listener);
}
/**
* Remove a previously installed window attach callback.
*
* @param victim The callback to remove
*
* @throws IllegalStateException If {@link #isAlive()} returns false
*
* @see #addOnWindowAttachListener(android.view.ViewTreeObserver.OnWindowAttachListener)
*/
public void removeOnWindowAttachListener(OnWindowAttachListener victim) {
checkIsAlive();
if (mOnWindowAttachListeners == null) {
return;
}
mOnWindowAttachListeners.remove(victim);
}
/**
* Register a callback to be invoked when the window focus state within the view tree changes.
*
* @param listener The callback to add
*
* @throws IllegalStateException If {@link #isAlive()} returns false
*/
public void addOnWindowFocusChangeListener(OnWindowFocusChangeListener listener) {
checkIsAlive();
if (mOnWindowFocusListeners == null) {
mOnWindowFocusListeners
= new CopyOnWriteArrayList<OnWindowFocusChangeListener>();
}
mOnWindowFocusListeners.add(listener);
}
/**
* Remove a previously installed window focus change callback.
*
* @param victim The callback to remove
*
* @throws IllegalStateException If {@link #isAlive()} returns false
*
* @see #addOnWindowFocusChangeListener(android.view.ViewTreeObserver.OnWindowFocusChangeListener)
*/
public void removeOnWindowFocusChangeListener(OnWindowFocusChangeListener victim) {
checkIsAlive();
if (mOnWindowFocusListeners == null) {
return;
}
mOnWindowFocusListeners.remove(victim);
}
/**
* Register a callback to be invoked when the focus state within the view tree changes.
*
@ -620,6 +738,41 @@ public final class ViewTreeObserver {
mAlive = false;
}
/**
* Notifies registered listeners that window has been attached/detached.
*/
final void dispatchOnWindowAttachedChange(boolean attached) {
// NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
// perform the dispatching. The iterator is a safe guard against listeners that
// could mutate the list by calling the various add/remove methods. This prevents
// the array from being modified while we iterate it.
final CopyOnWriteArrayList<OnWindowAttachListener> listeners
= mOnWindowAttachListeners;
if (listeners != null && listeners.size() > 0) {
for (OnWindowAttachListener listener : listeners) {
if (attached) listener.onWindowAttached();
else listener.onWindowDetached();
}
}
}
/**
* Notifies registered listeners that window focus has changed.
*/
final void dispatchOnWindowFocusChange(boolean hasFocus) {
// NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
// perform the dispatching. The iterator is a safe guard against listeners that
// could mutate the list by calling the various add/remove methods. This prevents
// the array from being modified while we iterate it.
final CopyOnWriteArrayList<OnWindowFocusChangeListener> listeners
= mOnWindowFocusListeners;
if (listeners != null && listeners.size() > 0) {
for (OnWindowFocusChangeListener listener : listeners) {
listener.onWindowFocusChanged(hasFocus);
}
}
}
/**
* Notifies registered listeners that focus has changed.
*/

View File

@ -2046,12 +2046,29 @@ public class AudioManager {
registerMediaButtonIntent(pi, eventReceiver);
}
/**
* Register a component to be the sole receiver of MEDIA_BUTTON intents. This is like
* {@link #registerMediaButtonEventReceiver(android.content.ComponentName)}, but allows
* the buttons to go to any PendingIntent. Note that you should only use this form if
* you know you will continue running for the full time until unregistering the
* PendingIntent.
* @param eventReceiver target that will receive media button intents. The PendingIntent
* will be sent as-is when a media button action occurs, with {@link Intent#EXTRA_KEY_EVENT}
* added and holding the key code of the media button that was pressed.
*/
public void registerMediaButtonEventReceiver(PendingIntent eventReceiver) {
if (eventReceiver == null) {
return;
}
registerMediaButtonIntent(eventReceiver, null);
}
/**
* @hide
* no-op if (pi == null) or (eventReceiver == null)
*/
public void registerMediaButtonIntent(PendingIntent pi, ComponentName eventReceiver) {
if ((pi == null) || (eventReceiver == null)) {
if (pi == null) {
Log.e(TAG, "Cannot call registerMediaButtonIntent() with a null parameter");
return;
}
@ -2113,6 +2130,18 @@ public class AudioManager {
unregisterMediaButtonIntent(pi, eventReceiver);
}
/**
* Unregister the receiver of MEDIA_BUTTON intents.
* @param eventReceiver same PendingIntent that was registed with
* {@link #registerMediaButtonEventReceiver(PendingIntent)}.
*/
public void unregisterMediaButtonEventReceiver(PendingIntent eventReceiver) {
if (eventReceiver == null) {
return;
}
unregisterMediaButtonIntent(eventReceiver, null);
}
/**
* @hide
*/

View File

@ -776,7 +776,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
}
}
/** @see AudioManager#adjustVolume(int, int, int) */
/** @see AudioManager#adjustVolume(int, int) */
public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) {
if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream="+suggestedStreamType);
int streamType;
@ -916,7 +916,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
sendVolumeUpdate(streamType, oldIndex, index, flags);
}
/** @see AudioManager#adjustMasterVolume(int) */
/** @see AudioManager#adjustMasterVolume(int, int) */
public void adjustMasterVolume(int steps, int flags) {
ensureValidSteps(steps);
int volume = Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
@ -1233,7 +1233,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
return (mStreamStates[streamType].muteCount() != 0);
}
/** @see AudioManager#setMasterMute(boolean, IBinder) */
/** @see AudioManager#setMasterMute(boolean, int) */
public void setMasterMute(boolean state, int flags, IBinder cb) {
if (state != AudioSystem.getMasterMute()) {
AudioSystem.setMasterMute(state);
@ -1315,7 +1315,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
return Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
}
/** @see AudioManager#getMasterStreamType(int) */
/** @see AudioManager#getMasterStreamType() */
public int getMasterStreamType() {
if (mVoiceCapable) {
return AudioSystem.STREAM_RING;
@ -1975,7 +1975,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
}
}
/** @see AudioManager#setSpeakerphoneOn() */
/** @see AudioManager#setSpeakerphoneOn(boolean) */
public void setSpeakerphoneOn(boolean on){
if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
return;
@ -1991,7 +1991,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
}
/** @see AudioManager#setBluetoothScoOn() */
/** @see AudioManager#setBluetoothScoOn(boolean) */
public void setBluetoothScoOn(boolean on){
if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
return;
@ -2009,7 +2009,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
}
/** @see AudioManager#setBluetoothA2dpOn() */
/** @see AudioManager#setBluetoothA2dpOn(boolean) */
public void setBluetoothA2dpOn(boolean on) {
synchronized (mBluetoothA2dpEnabledLock) {
mBluetoothA2dpEnabled = on;
@ -4127,7 +4127,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
AudioSystem.setParameters("screen_state=on");
} else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
AudioSystem.setParameters("screen_state=off");
} else if (action.equalsIgnoreCase(Intent.ACTION_CONFIGURATION_CHANGED)) {
} else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
handleConfigurationChanged(context);
} else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
// attempt to stop music playback for background user
@ -4296,7 +4296,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
* Helper function:
* Called synchronized on mAudioFocusLock
* Remove a focus listener from the focus stack.
* @param focusListenerToRemove the focus listener
* @param clientToRemove the focus listener
* @param signal if true and the listener was at the top of the focus stack, i.e. it was holding
* focus, notify the next item in the stack it gained focus.
*/
@ -4402,7 +4402,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
}
/** @see AudioManager#requestAudioFocus(IAudioFocusDispatcher, int, int) */
/** @see AudioManager#requestAudioFocus(AudioManager.OnAudioFocusChangeListener, int, int) */
public int requestAudioFocus(int mainStreamType, int focusChangeHint, IBinder cb,
IAudioFocusDispatcher fd, String clientId, String callingPackageName) {
Log.i(TAG, " AudioFocus requestAudioFocus() from " + clientId);
@ -4475,7 +4475,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
}
/** @see AudioManager#abandonAudioFocus(IAudioFocusDispatcher) */
/** @see AudioManager#abandonAudioFocus(AudioManager.OnAudioFocusChangeListener) */
public int abandonAudioFocus(IAudioFocusDispatcher fl, String clientId) {
Log.i(TAG, " AudioFocus abandonAudioFocus() from " + clientId);
try {
@ -4813,8 +4813,8 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
* remote control stack if necessary.
*/
private class RcClientDeathHandler implements IBinder.DeathRecipient {
private IBinder mCb; // To be notified of client's death
private PendingIntent mMediaIntent;
final private IBinder mCb; // To be notified of client's death
final private PendingIntent mMediaIntent;
RcClientDeathHandler(IBinder cb, PendingIntent pi) {
mCb = cb;
@ -4879,12 +4879,12 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
* The target for the ACTION_MEDIA_BUTTON events.
* Always non null.
*/
public PendingIntent mMediaIntent;
final public PendingIntent mMediaIntent;
/**
* The registered media button event receiver.
* Always non null.
*/
public ComponentName mReceiverComponent;
final public ComponentName mReceiverComponent;
public String mCallingPackageName;
public int mCallingUid;
/**
@ -5048,7 +5048,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
// evaluated it, traversal order doesn't matter here)
while(stackIterator.hasNext()) {
RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next();
if (packageName.equalsIgnoreCase(rcse.mReceiverComponent.getPackageName())) {
if (packageName.equals(rcse.mMediaIntent.getCreatorPackage())) {
// a stack entry is from the package being removed, remove it from the stack
stackIterator.remove();
rcse.unlinkToRcClientDeath();
@ -5061,10 +5061,14 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
null));
} else if (oldTop != mRCStack.peek()) {
// the top of the stack has changed, save it in the system settings
// by posting a message to persist it
mAudioHandler.sendMessage(
mAudioHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0,
mRCStack.peek().mReceiverComponent));
// by posting a message to persist it; only do this however if it has
// a concrete component name (is not a transient registration)
RemoteControlStackEntry rcse = mRCStack.peek();
if (rcse.mReceiverComponent != null) {
mAudioHandler.sendMessage(
mAudioHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0,
rcse.mReceiverComponent));
}
}
}
}
@ -5211,7 +5215,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
/**
* Update the displays and clients with the new "focused" client generation and name
* @param newClientGeneration the new generation value matching a client update
* @param newClientEventReceiver the media button event receiver associated with the client.
* @param newMediaIntent the media button event receiver associated with the client.
* May be null, which implies there is no registered media button event receiver.
* @param clearing true if the new client generation value maps to a remote control update
* where the display should be cleared.