16b05d58018c2806459c121e507c005639b74aee9Jim Miller/*
26b05d58018c2806459c121e507c005639b74aee9Jim Miller * Copyright (C) 2011 The Android Open Source Project
36b05d58018c2806459c121e507c005639b74aee9Jim Miller *
46b05d58018c2806459c121e507c005639b74aee9Jim Miller * Licensed under the Apache License, Version 2.0 (the "License");
56b05d58018c2806459c121e507c005639b74aee9Jim Miller * you may not use this file except in compliance with the License.
66b05d58018c2806459c121e507c005639b74aee9Jim Miller * You may obtain a copy of the License at
76b05d58018c2806459c121e507c005639b74aee9Jim Miller *
86b05d58018c2806459c121e507c005639b74aee9Jim Miller *      http://www.apache.org/licenses/LICENSE-2.0
96b05d58018c2806459c121e507c005639b74aee9Jim Miller *
106b05d58018c2806459c121e507c005639b74aee9Jim Miller * Unless required by applicable law or agreed to in writing, software
116b05d58018c2806459c121e507c005639b74aee9Jim Miller * distributed under the License is distributed on an "AS IS" BASIS,
126b05d58018c2806459c121e507c005639b74aee9Jim Miller * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136b05d58018c2806459c121e507c005639b74aee9Jim Miller * See the License for the specific language governing permissions and
146b05d58018c2806459c121e507c005639b74aee9Jim Miller * limitations under the License.
156b05d58018c2806459c121e507c005639b74aee9Jim Miller */
166b05d58018c2806459c121e507c005639b74aee9Jim Miller
176b05d58018c2806459c121e507c005639b74aee9Jim Millerpackage com.android.internal.widget;
186b05d58018c2806459c121e507c005639b74aee9Jim Miller
191c18828d20807342d37000746b18a3c1696f3b2eJim Millerimport java.lang.ref.WeakReference;
201c18828d20807342d37000746b18a3c1696f3b2eJim Miller
211c18828d20807342d37000746b18a3c1696f3b2eJim Millerimport com.android.internal.widget.LockScreenWidgetCallback;
221c18828d20807342d37000746b18a3c1696f3b2eJim Millerimport com.android.internal.widget.LockScreenWidgetInterface;
236b05d58018c2806459c121e507c005639b74aee9Jim Miller
24f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Triviimport android.app.PendingIntent;
25f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Triviimport android.app.PendingIntent.CanceledException;
266b05d58018c2806459c121e507c005639b74aee9Jim Millerimport android.content.Context;
271c18828d20807342d37000746b18a3c1696f3b2eJim Millerimport android.content.Intent;
281c18828d20807342d37000746b18a3c1696f3b2eJim Millerimport android.graphics.Bitmap;
296b05d58018c2806459c121e507c005639b74aee9Jim Millerimport android.media.AudioManager;
301c18828d20807342d37000746b18a3c1696f3b2eJim Millerimport android.media.MediaMetadataRetriever;
311c18828d20807342d37000746b18a3c1696f3b2eJim Millerimport android.media.RemoteControlClient;
321c18828d20807342d37000746b18a3c1696f3b2eJim Millerimport android.media.IRemoteControlDisplay;
331c18828d20807342d37000746b18a3c1696f3b2eJim Millerimport android.os.Bundle;
346b05d58018c2806459c121e507c005639b74aee9Jim Millerimport android.os.Handler;
356b05d58018c2806459c121e507c005639b74aee9Jim Millerimport android.os.Message;
364e6d35829ebf98ea37f77ea434550d51950c1119Jim Millerimport android.os.Parcel;
374e6d35829ebf98ea37f77ea434550d51950c1119Jim Millerimport android.os.Parcelable;
381c18828d20807342d37000746b18a3c1696f3b2eJim Millerimport android.os.RemoteException;
3968622396b62f9084781add1e12f4d513b633ab54Jean-Michel Triviimport android.os.SystemClock;
401c18828d20807342d37000746b18a3c1696f3b2eJim Millerimport android.text.Spannable;
411c18828d20807342d37000746b18a3c1696f3b2eJim Millerimport android.text.TextUtils;
421c18828d20807342d37000746b18a3c1696f3b2eJim Millerimport android.text.style.ForegroundColorSpan;
436b05d58018c2806459c121e507c005639b74aee9Jim Millerimport android.util.AttributeSet;
441c18828d20807342d37000746b18a3c1696f3b2eJim Millerimport android.util.Log;
451c18828d20807342d37000746b18a3c1696f3b2eJim Millerimport android.view.KeyEvent;
466b05d58018c2806459c121e507c005639b74aee9Jim Millerimport android.view.View;
476b05d58018c2806459c121e507c005639b74aee9Jim Millerimport android.view.View.OnClickListener;
481c18828d20807342d37000746b18a3c1696f3b2eJim Millerimport android.widget.FrameLayout;
491c18828d20807342d37000746b18a3c1696f3b2eJim Millerimport android.widget.ImageView;
501c18828d20807342d37000746b18a3c1696f3b2eJim Millerimport android.widget.TextView;
516b05d58018c2806459c121e507c005639b74aee9Jim Miller
526b05d58018c2806459c121e507c005639b74aee9Jim Miller
531c18828d20807342d37000746b18a3c1696f3b2eJim Millerimport com.android.internal.R;
541c18828d20807342d37000746b18a3c1696f3b2eJim Miller
551c18828d20807342d37000746b18a3c1696f3b2eJim Millerpublic class TransportControlView extends FrameLayout implements OnClickListener,
561c18828d20807342d37000746b18a3c1696f3b2eJim Miller        LockScreenWidgetInterface {
571c18828d20807342d37000746b18a3c1696f3b2eJim Miller
581c18828d20807342d37000746b18a3c1696f3b2eJim Miller    private static final int MSG_UPDATE_STATE = 100;
591c18828d20807342d37000746b18a3c1696f3b2eJim Miller    private static final int MSG_SET_METADATA = 101;
601c18828d20807342d37000746b18a3c1696f3b2eJim Miller    private static final int MSG_SET_TRANSPORT_CONTROLS = 102;
611c18828d20807342d37000746b18a3c1696f3b2eJim Miller    private static final int MSG_SET_ARTWORK = 103;
621c18828d20807342d37000746b18a3c1696f3b2eJim Miller    private static final int MSG_SET_GENERATION_ID = 104;
631c18828d20807342d37000746b18a3c1696f3b2eJim Miller    private static final int MAXDIM = 512;
6468622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi    private static final int DISPLAY_TIMEOUT_MS = 5000; // 5s
654e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller    protected static final boolean DEBUG = false;
661c18828d20807342d37000746b18a3c1696f3b2eJim Miller    protected static final String TAG = "TransportControlView";
671c18828d20807342d37000746b18a3c1696f3b2eJim Miller
681c18828d20807342d37000746b18a3c1696f3b2eJim Miller    private ImageView mAlbumArt;
691c18828d20807342d37000746b18a3c1696f3b2eJim Miller    private TextView mTrackTitle;
701c18828d20807342d37000746b18a3c1696f3b2eJim Miller    private ImageView mBtnPrev;
711c18828d20807342d37000746b18a3c1696f3b2eJim Miller    private ImageView mBtnPlay;
721c18828d20807342d37000746b18a3c1696f3b2eJim Miller    private ImageView mBtnNext;
731c18828d20807342d37000746b18a3c1696f3b2eJim Miller    private int mClientGeneration;
741c18828d20807342d37000746b18a3c1696f3b2eJim Miller    private Metadata mMetadata = new Metadata();
751c18828d20807342d37000746b18a3c1696f3b2eJim Miller    private boolean mAttached;
76f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi    private PendingIntent mClientIntent;
771c18828d20807342d37000746b18a3c1696f3b2eJim Miller    private int mTransportControlFlags;
784e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller    private int mCurrentPlayState;
791c18828d20807342d37000746b18a3c1696f3b2eJim Miller    private AudioManager mAudioManager;
801c18828d20807342d37000746b18a3c1696f3b2eJim Miller    private LockScreenWidgetCallback mWidgetCallbacks;
811c18828d20807342d37000746b18a3c1696f3b2eJim Miller    private IRemoteControlDisplayWeak mIRCD;
821c18828d20807342d37000746b18a3c1696f3b2eJim Miller
831c18828d20807342d37000746b18a3c1696f3b2eJim Miller    /**
841c18828d20807342d37000746b18a3c1696f3b2eJim Miller     * The metadata which should be populated into the view once we've been attached
851c18828d20807342d37000746b18a3c1696f3b2eJim Miller     */
861c18828d20807342d37000746b18a3c1696f3b2eJim Miller    private Bundle mPopulateMetadataWhenAttached = null;
871c18828d20807342d37000746b18a3c1696f3b2eJim Miller
881c18828d20807342d37000746b18a3c1696f3b2eJim Miller    // This handler is required to ensure messages from IRCD are handled in sequence and on
891c18828d20807342d37000746b18a3c1696f3b2eJim Miller    // the UI thread.
906b05d58018c2806459c121e507c005639b74aee9Jim Miller    private Handler mHandler = new Handler() {
911c18828d20807342d37000746b18a3c1696f3b2eJim Miller        @Override
926b05d58018c2806459c121e507c005639b74aee9Jim Miller        public void handleMessage(Message msg) {
931c18828d20807342d37000746b18a3c1696f3b2eJim Miller            switch (msg.what) {
941c18828d20807342d37000746b18a3c1696f3b2eJim Miller            case MSG_UPDATE_STATE:
951c18828d20807342d37000746b18a3c1696f3b2eJim Miller                if (mClientGeneration == msg.arg1) updatePlayPauseState(msg.arg2);
961c18828d20807342d37000746b18a3c1696f3b2eJim Miller                break;
971c18828d20807342d37000746b18a3c1696f3b2eJim Miller
981c18828d20807342d37000746b18a3c1696f3b2eJim Miller            case MSG_SET_METADATA:
991c18828d20807342d37000746b18a3c1696f3b2eJim Miller                if (mClientGeneration == msg.arg1) updateMetadata((Bundle) msg.obj);
1001c18828d20807342d37000746b18a3c1696f3b2eJim Miller                break;
1011c18828d20807342d37000746b18a3c1696f3b2eJim Miller
1021c18828d20807342d37000746b18a3c1696f3b2eJim Miller            case MSG_SET_TRANSPORT_CONTROLS:
1031c18828d20807342d37000746b18a3c1696f3b2eJim Miller                if (mClientGeneration == msg.arg1) updateTransportControls(msg.arg2);
1041c18828d20807342d37000746b18a3c1696f3b2eJim Miller                break;
1051c18828d20807342d37000746b18a3c1696f3b2eJim Miller
1061c18828d20807342d37000746b18a3c1696f3b2eJim Miller            case MSG_SET_ARTWORK:
1071c18828d20807342d37000746b18a3c1696f3b2eJim Miller                if (mClientGeneration == msg.arg1) {
10801d96bd2afdcff866e0e1010eb7c88e101d0f6faJean-Michel Trivi                    if (mMetadata.bitmap != null) {
10901d96bd2afdcff866e0e1010eb7c88e101d0f6faJean-Michel Trivi                        mMetadata.bitmap.recycle();
11001d96bd2afdcff866e0e1010eb7c88e101d0f6faJean-Michel Trivi                    }
1111c18828d20807342d37000746b18a3c1696f3b2eJim Miller                    mMetadata.bitmap = (Bitmap) msg.obj;
1121c18828d20807342d37000746b18a3c1696f3b2eJim Miller                    mAlbumArt.setImageBitmap(mMetadata.bitmap);
1131c18828d20807342d37000746b18a3c1696f3b2eJim Miller                }
1141c18828d20807342d37000746b18a3c1696f3b2eJim Miller                break;
1151c18828d20807342d37000746b18a3c1696f3b2eJim Miller
1161c18828d20807342d37000746b18a3c1696f3b2eJim Miller            case MSG_SET_GENERATION_ID:
1174e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller                if (msg.arg2 != 0) {
118a5ff5b482ab74b327983652439bea58c0499bae0Jim Miller                    // This means nobody is currently registered. Hide the view.
119a5ff5b482ab74b327983652439bea58c0499bae0Jim Miller                    if (mWidgetCallbacks != null) {
120a5ff5b482ab74b327983652439bea58c0499bae0Jim Miller                        mWidgetCallbacks.requestHide(TransportControlView.this);
121a5ff5b482ab74b327983652439bea58c0499bae0Jim Miller                    }
1221c18828d20807342d37000746b18a3c1696f3b2eJim Miller                }
1234e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller                if (DEBUG) Log.v(TAG, "New genId = " + msg.arg1 + ", clearing = " + msg.arg2);
1241c18828d20807342d37000746b18a3c1696f3b2eJim Miller                mClientGeneration = msg.arg1;
125f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi                mClientIntent = (PendingIntent) msg.obj;
1261c18828d20807342d37000746b18a3c1696f3b2eJim Miller                break;
1271c18828d20807342d37000746b18a3c1696f3b2eJim Miller
1286b05d58018c2806459c121e507c005639b74aee9Jim Miller            }
1296b05d58018c2806459c121e507c005639b74aee9Jim Miller        }
1306b05d58018c2806459c121e507c005639b74aee9Jim Miller    };
1316b05d58018c2806459c121e507c005639b74aee9Jim Miller
1321c18828d20807342d37000746b18a3c1696f3b2eJim Miller    /**
1331c18828d20807342d37000746b18a3c1696f3b2eJim Miller     * This class is required to have weak linkage to the current TransportControlView
1341c18828d20807342d37000746b18a3c1696f3b2eJim Miller     * because the remote process can hold a strong reference to this binder object and
1351c18828d20807342d37000746b18a3c1696f3b2eJim Miller     * we can't predict when it will be GC'd in the remote process. Without this code, it
1361c18828d20807342d37000746b18a3c1696f3b2eJim Miller     * would allow a heavyweight object to be held on this side of the binder when there's
1371c18828d20807342d37000746b18a3c1696f3b2eJim Miller     * no requirement to run a GC on the other side.
1381c18828d20807342d37000746b18a3c1696f3b2eJim Miller     */
1391c18828d20807342d37000746b18a3c1696f3b2eJim Miller    private static class IRemoteControlDisplayWeak extends IRemoteControlDisplay.Stub {
1401c18828d20807342d37000746b18a3c1696f3b2eJim Miller        private WeakReference<Handler> mLocalHandler;
1411c18828d20807342d37000746b18a3c1696f3b2eJim Miller
1421c18828d20807342d37000746b18a3c1696f3b2eJim Miller        IRemoteControlDisplayWeak(Handler handler) {
1431c18828d20807342d37000746b18a3c1696f3b2eJim Miller            mLocalHandler = new WeakReference<Handler>(handler);
1441c18828d20807342d37000746b18a3c1696f3b2eJim Miller        }
1451c18828d20807342d37000746b18a3c1696f3b2eJim Miller
14668622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi        public void setPlaybackState(int generationId, int state, long stateChangeTimeMs) {
1471c18828d20807342d37000746b18a3c1696f3b2eJim Miller            Handler handler = mLocalHandler.get();
1481c18828d20807342d37000746b18a3c1696f3b2eJim Miller            if (handler != null) {
1491c18828d20807342d37000746b18a3c1696f3b2eJim Miller                handler.obtainMessage(MSG_UPDATE_STATE, generationId, state).sendToTarget();
1506b05d58018c2806459c121e507c005639b74aee9Jim Miller            }
1511c18828d20807342d37000746b18a3c1696f3b2eJim Miller        }
1526b05d58018c2806459c121e507c005639b74aee9Jim Miller
1531c18828d20807342d37000746b18a3c1696f3b2eJim Miller        public void setMetadata(int generationId, Bundle metadata) {
1541c18828d20807342d37000746b18a3c1696f3b2eJim Miller            Handler handler = mLocalHandler.get();
1551c18828d20807342d37000746b18a3c1696f3b2eJim Miller            if (handler != null) {
1561c18828d20807342d37000746b18a3c1696f3b2eJim Miller                handler.obtainMessage(MSG_SET_METADATA, generationId, 0, metadata).sendToTarget();
1571c18828d20807342d37000746b18a3c1696f3b2eJim Miller            }
1581c18828d20807342d37000746b18a3c1696f3b2eJim Miller        }
1591c18828d20807342d37000746b18a3c1696f3b2eJim Miller
1601c18828d20807342d37000746b18a3c1696f3b2eJim Miller        public void setTransportControlFlags(int generationId, int flags) {
1611c18828d20807342d37000746b18a3c1696f3b2eJim Miller            Handler handler = mLocalHandler.get();
1621c18828d20807342d37000746b18a3c1696f3b2eJim Miller            if (handler != null) {
1631c18828d20807342d37000746b18a3c1696f3b2eJim Miller                handler.obtainMessage(MSG_SET_TRANSPORT_CONTROLS, generationId, flags)
1641c18828d20807342d37000746b18a3c1696f3b2eJim Miller                        .sendToTarget();
1651c18828d20807342d37000746b18a3c1696f3b2eJim Miller            }
1661c18828d20807342d37000746b18a3c1696f3b2eJim Miller        }
1671c18828d20807342d37000746b18a3c1696f3b2eJim Miller
1681c18828d20807342d37000746b18a3c1696f3b2eJim Miller        public void setArtwork(int generationId, Bitmap bitmap) {
1691c18828d20807342d37000746b18a3c1696f3b2eJim Miller            Handler handler = mLocalHandler.get();
1701c18828d20807342d37000746b18a3c1696f3b2eJim Miller            if (handler != null) {
1711c18828d20807342d37000746b18a3c1696f3b2eJim Miller                handler.obtainMessage(MSG_SET_ARTWORK, generationId, 0, bitmap).sendToTarget();
1721c18828d20807342d37000746b18a3c1696f3b2eJim Miller            }
1731c18828d20807342d37000746b18a3c1696f3b2eJim Miller        }
1741c18828d20807342d37000746b18a3c1696f3b2eJim Miller
1751c18828d20807342d37000746b18a3c1696f3b2eJim Miller        public void setAllMetadata(int generationId, Bundle metadata, Bitmap bitmap) {
1761c18828d20807342d37000746b18a3c1696f3b2eJim Miller            Handler handler = mLocalHandler.get();
1771c18828d20807342d37000746b18a3c1696f3b2eJim Miller            if (handler != null) {
1781c18828d20807342d37000746b18a3c1696f3b2eJim Miller                handler.obtainMessage(MSG_SET_METADATA, generationId, 0, metadata).sendToTarget();
1791c18828d20807342d37000746b18a3c1696f3b2eJim Miller                handler.obtainMessage(MSG_SET_ARTWORK, generationId, 0, bitmap).sendToTarget();
1801c18828d20807342d37000746b18a3c1696f3b2eJim Miller            }
1811c18828d20807342d37000746b18a3c1696f3b2eJim Miller        }
1821c18828d20807342d37000746b18a3c1696f3b2eJim Miller
183f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        public void setCurrentClientId(int clientGeneration, PendingIntent mediaIntent,
1841c18828d20807342d37000746b18a3c1696f3b2eJim Miller                boolean clearing) throws RemoteException {
1851c18828d20807342d37000746b18a3c1696f3b2eJim Miller            Handler handler = mLocalHandler.get();
1861c18828d20807342d37000746b18a3c1696f3b2eJim Miller            if (handler != null) {
1871c18828d20807342d37000746b18a3c1696f3b2eJim Miller                handler.obtainMessage(MSG_SET_GENERATION_ID,
188f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi                    clientGeneration, (clearing ? 1 : 0), mediaIntent).sendToTarget();
1891c18828d20807342d37000746b18a3c1696f3b2eJim Miller            }
1901c18828d20807342d37000746b18a3c1696f3b2eJim Miller        }
1911c18828d20807342d37000746b18a3c1696f3b2eJim Miller    };
1926b05d58018c2806459c121e507c005639b74aee9Jim Miller
1936b05d58018c2806459c121e507c005639b74aee9Jim Miller    public TransportControlView(Context context, AttributeSet attrs) {
1946b05d58018c2806459c121e507c005639b74aee9Jim Miller        super(context, attrs);
1957ff30113de68539ec840c524b8f1561f938f96c5Dianne Hackborn        if (DEBUG) Log.v(TAG, "Create TCV " + this);
1961c18828d20807342d37000746b18a3c1696f3b2eJim Miller        mAudioManager = new AudioManager(mContext);
1974e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller        mCurrentPlayState = RemoteControlClient.PLAYSTATE_NONE; // until we get a callback
1981c18828d20807342d37000746b18a3c1696f3b2eJim Miller        mIRCD = new IRemoteControlDisplayWeak(mHandler);
1996b05d58018c2806459c121e507c005639b74aee9Jim Miller    }
2006b05d58018c2806459c121e507c005639b74aee9Jim Miller
2011c18828d20807342d37000746b18a3c1696f3b2eJim Miller    private void updateTransportControls(int transportControlFlags) {
2021c18828d20807342d37000746b18a3c1696f3b2eJim Miller        mTransportControlFlags = transportControlFlags;
2036b05d58018c2806459c121e507c005639b74aee9Jim Miller    }
2046b05d58018c2806459c121e507c005639b74aee9Jim Miller
2051c18828d20807342d37000746b18a3c1696f3b2eJim Miller    @Override
2061c18828d20807342d37000746b18a3c1696f3b2eJim Miller    public void onFinishInflate() {
2071c18828d20807342d37000746b18a3c1696f3b2eJim Miller        super.onFinishInflate();
2081c18828d20807342d37000746b18a3c1696f3b2eJim Miller        mTrackTitle = (TextView) findViewById(R.id.title);
2091c18828d20807342d37000746b18a3c1696f3b2eJim Miller        mTrackTitle.setSelected(true); // enable marquee
2101c18828d20807342d37000746b18a3c1696f3b2eJim Miller        mAlbumArt = (ImageView) findViewById(R.id.albumart);
2111c18828d20807342d37000746b18a3c1696f3b2eJim Miller        mBtnPrev = (ImageView) findViewById(R.id.btn_prev);
2121c18828d20807342d37000746b18a3c1696f3b2eJim Miller        mBtnPlay = (ImageView) findViewById(R.id.btn_play);
2131c18828d20807342d37000746b18a3c1696f3b2eJim Miller        mBtnNext = (ImageView) findViewById(R.id.btn_next);
2141c18828d20807342d37000746b18a3c1696f3b2eJim Miller        final View buttons[] = { mBtnPrev, mBtnPlay, mBtnNext };
2151c18828d20807342d37000746b18a3c1696f3b2eJim Miller        for (View view : buttons) {
2161c18828d20807342d37000746b18a3c1696f3b2eJim Miller            view.setOnClickListener(this);
2171c18828d20807342d37000746b18a3c1696f3b2eJim Miller        }
2186b05d58018c2806459c121e507c005639b74aee9Jim Miller    }
2196b05d58018c2806459c121e507c005639b74aee9Jim Miller
2206b05d58018c2806459c121e507c005639b74aee9Jim Miller    @Override
2211c18828d20807342d37000746b18a3c1696f3b2eJim Miller    public void onAttachedToWindow() {
2221c18828d20807342d37000746b18a3c1696f3b2eJim Miller        super.onAttachedToWindow();
2231c18828d20807342d37000746b18a3c1696f3b2eJim Miller        if (mPopulateMetadataWhenAttached != null) {
2241c18828d20807342d37000746b18a3c1696f3b2eJim Miller            updateMetadata(mPopulateMetadataWhenAttached);
2251c18828d20807342d37000746b18a3c1696f3b2eJim Miller            mPopulateMetadataWhenAttached = null;
2261c18828d20807342d37000746b18a3c1696f3b2eJim Miller        }
2271c18828d20807342d37000746b18a3c1696f3b2eJim Miller        if (!mAttached) {
2281c18828d20807342d37000746b18a3c1696f3b2eJim Miller            if (DEBUG) Log.v(TAG, "Registering TCV " + this);
2291c18828d20807342d37000746b18a3c1696f3b2eJim Miller            mAudioManager.registerRemoteControlDisplay(mIRCD);
2301c18828d20807342d37000746b18a3c1696f3b2eJim Miller        }
2311c18828d20807342d37000746b18a3c1696f3b2eJim Miller        mAttached = true;
2321c18828d20807342d37000746b18a3c1696f3b2eJim Miller    }
2331c18828d20807342d37000746b18a3c1696f3b2eJim Miller
2341c18828d20807342d37000746b18a3c1696f3b2eJim Miller    @Override
2351c18828d20807342d37000746b18a3c1696f3b2eJim Miller    public void onDetachedFromWindow() {
2361c18828d20807342d37000746b18a3c1696f3b2eJim Miller        super.onDetachedFromWindow();
2371c18828d20807342d37000746b18a3c1696f3b2eJim Miller        if (mAttached) {
2381c18828d20807342d37000746b18a3c1696f3b2eJim Miller            if (DEBUG) Log.v(TAG, "Unregistering TCV " + this);
2391c18828d20807342d37000746b18a3c1696f3b2eJim Miller            mAudioManager.unregisterRemoteControlDisplay(mIRCD);
2401c18828d20807342d37000746b18a3c1696f3b2eJim Miller        }
2411c18828d20807342d37000746b18a3c1696f3b2eJim Miller        mAttached = false;
2421c18828d20807342d37000746b18a3c1696f3b2eJim Miller    }
2431c18828d20807342d37000746b18a3c1696f3b2eJim Miller
2441c18828d20807342d37000746b18a3c1696f3b2eJim Miller    @Override
2451c18828d20807342d37000746b18a3c1696f3b2eJim Miller    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
2461c18828d20807342d37000746b18a3c1696f3b2eJim Miller        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
2471c18828d20807342d37000746b18a3c1696f3b2eJim Miller        int dim = Math.min(MAXDIM, Math.max(getWidth(), getHeight()));
2481c18828d20807342d37000746b18a3c1696f3b2eJim Miller//        Log.v(TAG, "setting max bitmap size: " + dim + "x" + dim);
2491c18828d20807342d37000746b18a3c1696f3b2eJim Miller//        mAudioManager.remoteControlDisplayUsesBitmapSize(mIRCD, dim, dim);
2501c18828d20807342d37000746b18a3c1696f3b2eJim Miller    }
2511c18828d20807342d37000746b18a3c1696f3b2eJim Miller
2521c18828d20807342d37000746b18a3c1696f3b2eJim Miller    class Metadata {
2531c18828d20807342d37000746b18a3c1696f3b2eJim Miller        private String artist;
2541c18828d20807342d37000746b18a3c1696f3b2eJim Miller        private String trackTitle;
2551c18828d20807342d37000746b18a3c1696f3b2eJim Miller        private String albumTitle;
2561c18828d20807342d37000746b18a3c1696f3b2eJim Miller        private Bitmap bitmap;
2571c18828d20807342d37000746b18a3c1696f3b2eJim Miller
2581c18828d20807342d37000746b18a3c1696f3b2eJim Miller        public String toString() {
2591c18828d20807342d37000746b18a3c1696f3b2eJim Miller            return "Metadata[artist=" + artist + " trackTitle=" + trackTitle + " albumTitle=" + albumTitle + "]";
2601c18828d20807342d37000746b18a3c1696f3b2eJim Miller        }
2611c18828d20807342d37000746b18a3c1696f3b2eJim Miller    }
2621c18828d20807342d37000746b18a3c1696f3b2eJim Miller
2631c18828d20807342d37000746b18a3c1696f3b2eJim Miller    private String getMdString(Bundle data, int id) {
2641c18828d20807342d37000746b18a3c1696f3b2eJim Miller        return data.getString(Integer.toString(id));
2651c18828d20807342d37000746b18a3c1696f3b2eJim Miller    }
2661c18828d20807342d37000746b18a3c1696f3b2eJim Miller
2671c18828d20807342d37000746b18a3c1696f3b2eJim Miller    private void updateMetadata(Bundle data) {
2681c18828d20807342d37000746b18a3c1696f3b2eJim Miller        if (mAttached) {
2691c18828d20807342d37000746b18a3c1696f3b2eJim Miller            mMetadata.artist = getMdString(data, MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST);
2701c18828d20807342d37000746b18a3c1696f3b2eJim Miller            mMetadata.trackTitle = getMdString(data, MediaMetadataRetriever.METADATA_KEY_TITLE);
2711c18828d20807342d37000746b18a3c1696f3b2eJim Miller            mMetadata.albumTitle = getMdString(data, MediaMetadataRetriever.METADATA_KEY_ALBUM);
2721c18828d20807342d37000746b18a3c1696f3b2eJim Miller            populateMetadata();
2731c18828d20807342d37000746b18a3c1696f3b2eJim Miller        } else {
2741c18828d20807342d37000746b18a3c1696f3b2eJim Miller            mPopulateMetadataWhenAttached = data;
2751c18828d20807342d37000746b18a3c1696f3b2eJim Miller        }
2761c18828d20807342d37000746b18a3c1696f3b2eJim Miller    }
2771c18828d20807342d37000746b18a3c1696f3b2eJim Miller
2781c18828d20807342d37000746b18a3c1696f3b2eJim Miller    /**
2791c18828d20807342d37000746b18a3c1696f3b2eJim Miller     * Populates the given metadata into the view
2801c18828d20807342d37000746b18a3c1696f3b2eJim Miller     */
2811c18828d20807342d37000746b18a3c1696f3b2eJim Miller    private void populateMetadata() {
2821c18828d20807342d37000746b18a3c1696f3b2eJim Miller        StringBuilder sb = new StringBuilder();
2831c18828d20807342d37000746b18a3c1696f3b2eJim Miller        int trackTitleLength = 0;
2841c18828d20807342d37000746b18a3c1696f3b2eJim Miller        if (!TextUtils.isEmpty(mMetadata.trackTitle)) {
2851c18828d20807342d37000746b18a3c1696f3b2eJim Miller            sb.append(mMetadata.trackTitle);
2861c18828d20807342d37000746b18a3c1696f3b2eJim Miller            trackTitleLength = mMetadata.trackTitle.length();
2871c18828d20807342d37000746b18a3c1696f3b2eJim Miller        }
2881c18828d20807342d37000746b18a3c1696f3b2eJim Miller        if (!TextUtils.isEmpty(mMetadata.artist)) {
2891c18828d20807342d37000746b18a3c1696f3b2eJim Miller            if (sb.length() != 0) {
2901c18828d20807342d37000746b18a3c1696f3b2eJim Miller                sb.append(" - ");
2911c18828d20807342d37000746b18a3c1696f3b2eJim Miller            }
2921c18828d20807342d37000746b18a3c1696f3b2eJim Miller            sb.append(mMetadata.artist);
2931c18828d20807342d37000746b18a3c1696f3b2eJim Miller        }
2941c18828d20807342d37000746b18a3c1696f3b2eJim Miller        if (!TextUtils.isEmpty(mMetadata.albumTitle)) {
2951c18828d20807342d37000746b18a3c1696f3b2eJim Miller            if (sb.length() != 0) {
2961c18828d20807342d37000746b18a3c1696f3b2eJim Miller                sb.append(" - ");
2976b05d58018c2806459c121e507c005639b74aee9Jim Miller            }
2981c18828d20807342d37000746b18a3c1696f3b2eJim Miller            sb.append(mMetadata.albumTitle);
2991c18828d20807342d37000746b18a3c1696f3b2eJim Miller        }
3001c18828d20807342d37000746b18a3c1696f3b2eJim Miller        mTrackTitle.setText(sb.toString(), TextView.BufferType.SPANNABLE);
3011c18828d20807342d37000746b18a3c1696f3b2eJim Miller        Spannable str = (Spannable) mTrackTitle.getText();
3021c18828d20807342d37000746b18a3c1696f3b2eJim Miller        if (trackTitleLength != 0) {
3031c18828d20807342d37000746b18a3c1696f3b2eJim Miller            str.setSpan(new ForegroundColorSpan(0xffffffff), 0, trackTitleLength,
3041c18828d20807342d37000746b18a3c1696f3b2eJim Miller                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
3051c18828d20807342d37000746b18a3c1696f3b2eJim Miller            trackTitleLength++;
3061c18828d20807342d37000746b18a3c1696f3b2eJim Miller        }
3071c18828d20807342d37000746b18a3c1696f3b2eJim Miller        if (sb.length() > trackTitleLength) {
3081c18828d20807342d37000746b18a3c1696f3b2eJim Miller            str.setSpan(new ForegroundColorSpan(0x7fffffff), trackTitleLength, sb.length(),
3091c18828d20807342d37000746b18a3c1696f3b2eJim Miller                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
3106b05d58018c2806459c121e507c005639b74aee9Jim Miller        }
3111c18828d20807342d37000746b18a3c1696f3b2eJim Miller
3121c18828d20807342d37000746b18a3c1696f3b2eJim Miller        mAlbumArt.setImageBitmap(mMetadata.bitmap);
3131c18828d20807342d37000746b18a3c1696f3b2eJim Miller        final int flags = mTransportControlFlags;
3141c18828d20807342d37000746b18a3c1696f3b2eJim Miller        setVisibilityBasedOnFlag(mBtnPrev, flags, RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS);
3151c18828d20807342d37000746b18a3c1696f3b2eJim Miller        setVisibilityBasedOnFlag(mBtnNext, flags, RemoteControlClient.FLAG_KEY_MEDIA_NEXT);
3161f0eac9951c7167ee9f07251d1ef60805b96bffdJim Miller        setVisibilityBasedOnFlag(mBtnPlay, flags,
3171c18828d20807342d37000746b18a3c1696f3b2eJim Miller                RemoteControlClient.FLAG_KEY_MEDIA_PLAY
3181c18828d20807342d37000746b18a3c1696f3b2eJim Miller                | RemoteControlClient.FLAG_KEY_MEDIA_PAUSE
3191c18828d20807342d37000746b18a3c1696f3b2eJim Miller                | RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE
3201c18828d20807342d37000746b18a3c1696f3b2eJim Miller                | RemoteControlClient.FLAG_KEY_MEDIA_STOP);
3211c18828d20807342d37000746b18a3c1696f3b2eJim Miller
3224e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller        updatePlayPauseState(mCurrentPlayState);
3236b05d58018c2806459c121e507c005639b74aee9Jim Miller    }
3246b05d58018c2806459c121e507c005639b74aee9Jim Miller
3251c18828d20807342d37000746b18a3c1696f3b2eJim Miller    private static void setVisibilityBasedOnFlag(View view, int flags, int flag) {
3261c18828d20807342d37000746b18a3c1696f3b2eJim Miller        if ((flags & flag) != 0) {
3271c18828d20807342d37000746b18a3c1696f3b2eJim Miller            view.setVisibility(View.VISIBLE);
3281c18828d20807342d37000746b18a3c1696f3b2eJim Miller        } else {
3291c18828d20807342d37000746b18a3c1696f3b2eJim Miller            view.setVisibility(View.GONE);
3301c18828d20807342d37000746b18a3c1696f3b2eJim Miller        }
3311c18828d20807342d37000746b18a3c1696f3b2eJim Miller    }
3321c18828d20807342d37000746b18a3c1696f3b2eJim Miller
3331c18828d20807342d37000746b18a3c1696f3b2eJim Miller    private void updatePlayPauseState(int state) {
3341c18828d20807342d37000746b18a3c1696f3b2eJim Miller        if (DEBUG) Log.v(TAG,
3354e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller                "updatePlayPauseState(), old=" + mCurrentPlayState + ", state=" + state);
3364e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller        if (state == mCurrentPlayState) {
3371c18828d20807342d37000746b18a3c1696f3b2eJim Miller            return;
3381c18828d20807342d37000746b18a3c1696f3b2eJim Miller        }
33967e043db11b29f3c0c84529ae21a0fdd7ae11c6dJim Miller        final int imageResId;
34067e043db11b29f3c0c84529ae21a0fdd7ae11c6dJim Miller        final int imageDescId;
34183e160d3b3ad839b0c2faf40f4477a2468098995Jim Miller        boolean showIfHidden = false;
3421c18828d20807342d37000746b18a3c1696f3b2eJim Miller        switch (state) {
343261381cf9f52776f5f5fad8e6d2d31960c60c945Jean-Michel Trivi            case RemoteControlClient.PLAYSTATE_ERROR:
344261381cf9f52776f5f5fad8e6d2d31960c60c945Jean-Michel Trivi                imageResId = com.android.internal.R.drawable.stat_sys_warning;
345261381cf9f52776f5f5fad8e6d2d31960c60c945Jean-Michel Trivi                // TODO use more specific image description string for warning, but here the "play"
346261381cf9f52776f5f5fad8e6d2d31960c60c945Jean-Michel Trivi                //      message is still valid because this button triggers a play command.
347261381cf9f52776f5f5fad8e6d2d31960c60c945Jean-Michel Trivi                imageDescId = com.android.internal.R.string.lockscreen_transport_play_description;
348261381cf9f52776f5f5fad8e6d2d31960c60c945Jean-Michel Trivi                break;
349261381cf9f52776f5f5fad8e6d2d31960c60c945Jean-Michel Trivi
3501c18828d20807342d37000746b18a3c1696f3b2eJim Miller            case RemoteControlClient.PLAYSTATE_PLAYING:
35167e043db11b29f3c0c84529ae21a0fdd7ae11c6dJim Miller                imageResId = com.android.internal.R.drawable.ic_media_pause;
35267e043db11b29f3c0c84529ae21a0fdd7ae11c6dJim Miller                imageDescId = com.android.internal.R.string.lockscreen_transport_pause_description;
3534e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller                showIfHidden = true;
3546b05d58018c2806459c121e507c005639b74aee9Jim Miller                break;
3556b05d58018c2806459c121e507c005639b74aee9Jim Miller
3561c18828d20807342d37000746b18a3c1696f3b2eJim Miller            case RemoteControlClient.PLAYSTATE_BUFFERING:
35767e043db11b29f3c0c84529ae21a0fdd7ae11c6dJim Miller                imageResId = com.android.internal.R.drawable.ic_media_stop;
35867e043db11b29f3c0c84529ae21a0fdd7ae11c6dJim Miller                imageDescId = com.android.internal.R.string.lockscreen_transport_stop_description;
3594e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller                showIfHidden = true;
3606b05d58018c2806459c121e507c005639b74aee9Jim Miller                break;
3616b05d58018c2806459c121e507c005639b74aee9Jim Miller
3621c18828d20807342d37000746b18a3c1696f3b2eJim Miller            case RemoteControlClient.PLAYSTATE_PAUSED:
3631c18828d20807342d37000746b18a3c1696f3b2eJim Miller            default:
36467e043db11b29f3c0c84529ae21a0fdd7ae11c6dJim Miller                imageResId = com.android.internal.R.drawable.ic_media_play;
36567e043db11b29f3c0c84529ae21a0fdd7ae11c6dJim Miller                imageDescId = com.android.internal.R.string.lockscreen_transport_play_description;
3664e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller                showIfHidden = false;
3676b05d58018c2806459c121e507c005639b74aee9Jim Miller                break;
3686b05d58018c2806459c121e507c005639b74aee9Jim Miller        }
36967e043db11b29f3c0c84529ae21a0fdd7ae11c6dJim Miller        mBtnPlay.setImageResource(imageResId);
37067e043db11b29f3c0c84529ae21a0fdd7ae11c6dJim Miller        mBtnPlay.setContentDescription(getResources().getString(imageDescId));
3714e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller        if (showIfHidden && mWidgetCallbacks != null && !mWidgetCallbacks.isVisible(this)) {
3724e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller            mWidgetCallbacks.requestShow(this);
3734e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller        }
3744e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller        mCurrentPlayState = state;
3754e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller    }
3764e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller
3774e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller    static class SavedState extends BaseSavedState {
3784e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller        boolean wasShowing;
3794e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller
3804e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller        SavedState(Parcelable superState) {
3814e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller            super(superState);
3824e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller        }
3834e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller
3844e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller        private SavedState(Parcel in) {
3854e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller            super(in);
3864e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller            this.wasShowing = in.readInt() != 0;
3874e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller        }
3884e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller
3894e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller        @Override
3904e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller        public void writeToParcel(Parcel out, int flags) {
3914e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller            super.writeToParcel(out, flags);
3924e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller            out.writeInt(this.wasShowing ? 1 : 0);
3934e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller        }
3944e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller
3954e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller        public static final Parcelable.Creator<SavedState> CREATOR
3964e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller                = new Parcelable.Creator<SavedState>() {
3974e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller            public SavedState createFromParcel(Parcel in) {
3984e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller                return new SavedState(in);
3994e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller            }
4004e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller
4014e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller            public SavedState[] newArray(int size) {
4024e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller                return new SavedState[size];
4034e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller            }
4044e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller        };
4054e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller    }
4064e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller
4074e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller    @Override
4084e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller    public Parcelable onSaveInstanceState() {
4094e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller        if (DEBUG) Log.v(TAG, "onSaveInstanceState()");
4104e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller        Parcelable superState = super.onSaveInstanceState();
4114e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller        SavedState ss = new SavedState(superState);
412a5ff5b482ab74b327983652439bea58c0499bae0Jim Miller        ss.wasShowing = mWidgetCallbacks != null && mWidgetCallbacks.isVisible(this);
4134e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller        return ss;
4144e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller    }
4154e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller
4164e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller    @Override
4174e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller    public void onRestoreInstanceState(Parcelable state) {
4184e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller        if (DEBUG) Log.v(TAG, "onRestoreInstanceState()");
4194e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller        if (!(state instanceof SavedState)) {
4204e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller            super.onRestoreInstanceState(state);
4214e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller            return;
4224e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller        }
4234e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller        SavedState ss = (SavedState) state;
4244e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller        super.onRestoreInstanceState(ss.getSuperState());
425a5ff5b482ab74b327983652439bea58c0499bae0Jim Miller        if (ss.wasShowing && mWidgetCallbacks != null) {
4264e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller            mWidgetCallbacks.requestShow(this);
4274e6d35829ebf98ea37f77ea434550d51950c1119Jim Miller        }
4281c18828d20807342d37000746b18a3c1696f3b2eJim Miller    }
4291c18828d20807342d37000746b18a3c1696f3b2eJim Miller
4301c18828d20807342d37000746b18a3c1696f3b2eJim Miller    public void onClick(View v) {
4311c18828d20807342d37000746b18a3c1696f3b2eJim Miller        int keyCode = -1;
4321c18828d20807342d37000746b18a3c1696f3b2eJim Miller        if (v == mBtnPrev) {
4331c18828d20807342d37000746b18a3c1696f3b2eJim Miller            keyCode = KeyEvent.KEYCODE_MEDIA_PREVIOUS;
4341c18828d20807342d37000746b18a3c1696f3b2eJim Miller        } else if (v == mBtnNext) {
4351c18828d20807342d37000746b18a3c1696f3b2eJim Miller            keyCode = KeyEvent.KEYCODE_MEDIA_NEXT;
4361c18828d20807342d37000746b18a3c1696f3b2eJim Miller        } else if (v == mBtnPlay) {
4371c18828d20807342d37000746b18a3c1696f3b2eJim Miller            keyCode = KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE;
4381c18828d20807342d37000746b18a3c1696f3b2eJim Miller
4391c18828d20807342d37000746b18a3c1696f3b2eJim Miller        }
4401c18828d20807342d37000746b18a3c1696f3b2eJim Miller        if (keyCode != -1) {
4411c18828d20807342d37000746b18a3c1696f3b2eJim Miller            sendMediaButtonClick(keyCode);
4421c18828d20807342d37000746b18a3c1696f3b2eJim Miller            if (mWidgetCallbacks != null) {
4431c18828d20807342d37000746b18a3c1696f3b2eJim Miller                mWidgetCallbacks.userActivity(this);
4441c18828d20807342d37000746b18a3c1696f3b2eJim Miller            }
4456b05d58018c2806459c121e507c005639b74aee9Jim Miller        }
4466b05d58018c2806459c121e507c005639b74aee9Jim Miller    }
4476b05d58018c2806459c121e507c005639b74aee9Jim Miller
4481c18828d20807342d37000746b18a3c1696f3b2eJim Miller    private void sendMediaButtonClick(int keyCode) {
449a5ff5b482ab74b327983652439bea58c0499bae0Jim Miller        if (mClientIntent == null) {
450a5ff5b482ab74b327983652439bea58c0499bae0Jim Miller            // Shouldn't be possible because this view should be hidden in this case.
451a5ff5b482ab74b327983652439bea58c0499bae0Jim Miller            Log.e(TAG, "sendMediaButtonClick(): No client is currently registered");
452a5ff5b482ab74b327983652439bea58c0499bae0Jim Miller            return;
453a5ff5b482ab74b327983652439bea58c0499bae0Jim Miller        }
454f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        // use the registered PendingIntent that will be processed by the registered
455f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        //    media button event receiver, which is the component of mClientIntent
4561c18828d20807342d37000746b18a3c1696f3b2eJim Miller        KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
4571c18828d20807342d37000746b18a3c1696f3b2eJim Miller        Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
4581c18828d20807342d37000746b18a3c1696f3b2eJim Miller        intent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
459f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        try {
460f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            mClientIntent.send(getContext(), 0, intent);
461f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        } catch (CanceledException e) {
462f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            Log.e(TAG, "Error sending intent for media button down: "+e);
463f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            e.printStackTrace();
464f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        }
4651c18828d20807342d37000746b18a3c1696f3b2eJim Miller
4661c18828d20807342d37000746b18a3c1696f3b2eJim Miller        keyEvent = new KeyEvent(KeyEvent.ACTION_UP, keyCode);
4671c18828d20807342d37000746b18a3c1696f3b2eJim Miller        intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
4681c18828d20807342d37000746b18a3c1696f3b2eJim Miller        intent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
469f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        try {
470f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            mClientIntent.send(getContext(), 0, intent);
471f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        } catch (CanceledException e) {
472f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            Log.e(TAG, "Error sending intent for media button up: "+e);
473f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            e.printStackTrace();
474f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        }
4751c18828d20807342d37000746b18a3c1696f3b2eJim Miller    }
4761c18828d20807342d37000746b18a3c1696f3b2eJim Miller
4771c18828d20807342d37000746b18a3c1696f3b2eJim Miller    public void setCallback(LockScreenWidgetCallback callback) {
4781c18828d20807342d37000746b18a3c1696f3b2eJim Miller        mWidgetCallbacks = callback;
4791c18828d20807342d37000746b18a3c1696f3b2eJim Miller    }
4801c18828d20807342d37000746b18a3c1696f3b2eJim Miller
481054340d0a3f242efeaf898cca38625bdcb3b4b5aJeff Sharkey    public boolean providesClock() {
482054340d0a3f242efeaf898cca38625bdcb3b4b5aJeff Sharkey        return false;
483054340d0a3f242efeaf898cca38625bdcb3b4b5aJeff Sharkey    }
484054340d0a3f242efeaf898cca38625bdcb3b4b5aJeff Sharkey
48568622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi    private boolean wasPlayingRecently(int state, long stateChangeTimeMs) {
48668622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi        switch (state) {
48768622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi            case RemoteControlClient.PLAYSTATE_PLAYING:
48868622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi            case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
48968622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi            case RemoteControlClient.PLAYSTATE_REWINDING:
49068622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi            case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
49168622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi            case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
49268622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi            case RemoteControlClient.PLAYSTATE_BUFFERING:
49368622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi                // actively playing or about to play
49468622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi                return true;
49568622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi            case RemoteControlClient.PLAYSTATE_NONE:
49668622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi                return false;
49768622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi            case RemoteControlClient.PLAYSTATE_STOPPED:
49868622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi            case RemoteControlClient.PLAYSTATE_PAUSED:
49968622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi            case RemoteControlClient.PLAYSTATE_ERROR:
50068622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi                // we have stopped playing, check how long ago
50168622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi                if (DEBUG) {
50268622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi                    if ((SystemClock.elapsedRealtime() - stateChangeTimeMs) < DISPLAY_TIMEOUT_MS) {
50368622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi                        Log.v(TAG, "wasPlayingRecently: time < TIMEOUT was playing recently");
50468622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi                    } else {
50568622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi                        Log.v(TAG, "wasPlayingRecently: time > TIMEOUT");
50668622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi                    }
50768622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi                }
50868622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi                return ((SystemClock.elapsedRealtime() - stateChangeTimeMs) < DISPLAY_TIMEOUT_MS);
50968622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi            default:
51068622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi                Log.e(TAG, "Unknown playback state " + state + " in wasPlayingRecently()");
51168622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi                return false;
51268622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi        }
51368622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi    }
5146b05d58018c2806459c121e507c005639b74aee9Jim Miller}
515