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

Commit 1a89c532 authored by Dianne Hackborn's avatar Dianne Hackborn Committed by Android (Google) Code Review
Browse files

Merge "New media button API." into jb-mr2-dev

parents 5341f377 961cae92
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -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);
+3 −0
Original line number Diff line number Diff line
@@ -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,
+153 −0
Original line number Diff line number Diff line
@@ -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.
     */
+30 −1
Original line number Diff line number Diff line
@@ -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
     */
+25 −21
Original line number Diff line number Diff line
@@ -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
                    // 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,
                                    mRCStack.peek().mReceiverComponent));
                                        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.