blob: ca797ebc3ee371a3af0a7ae88febb7f9e8ea6edb [file] [log] [blame]
Jim Miller6b05d582011-07-18 13:09:59 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.internal.widget;
18
Jim Miller1c188282011-08-08 22:27:58 -070019import java.lang.ref.WeakReference;
Jim Miller6b05d582011-07-18 13:09:59 -070020
Jim Miller1c188282011-08-08 22:27:58 -070021import com.android.internal.widget.LockScreenWidgetCallback;
22import com.android.internal.widget.LockScreenWidgetInterface;
23
Jean-Michel Trivif0cff042011-09-14 18:11:09 -070024import android.app.PendingIntent;
25import android.app.PendingIntent.CanceledException;
Jim Miller6b05d582011-07-18 13:09:59 -070026import android.content.Context;
Jim Miller1c188282011-08-08 22:27:58 -070027import android.content.Intent;
28import android.graphics.Bitmap;
Jim Miller6b05d582011-07-18 13:09:59 -070029import android.media.AudioManager;
Jim Miller1c188282011-08-08 22:27:58 -070030import android.media.MediaMetadataRetriever;
31import android.media.RemoteControlClient;
32import android.media.IRemoteControlDisplay;
33import android.os.Bundle;
Jim Miller6b05d582011-07-18 13:09:59 -070034import android.os.Handler;
35import android.os.Message;
Jim Miller4e6d3582011-10-13 18:22:13 -070036import android.os.Parcel;
37import android.os.Parcelable;
Jim Miller1c188282011-08-08 22:27:58 -070038import android.os.RemoteException;
Jean-Michel Trivi68622392011-09-19 14:53:14 -070039import android.os.SystemClock;
Jim Miller1c188282011-08-08 22:27:58 -070040import android.text.Spannable;
41import android.text.TextUtils;
42import android.text.style.ForegroundColorSpan;
Jim Miller6b05d582011-07-18 13:09:59 -070043import android.util.AttributeSet;
Jim Miller1c188282011-08-08 22:27:58 -070044import android.util.Log;
45import android.view.KeyEvent;
Jim Miller6b05d582011-07-18 13:09:59 -070046import android.view.View;
47import android.view.View.OnClickListener;
Jim Miller1c188282011-08-08 22:27:58 -070048import android.widget.FrameLayout;
49import android.widget.ImageView;
50import android.widget.TextView;
Jim Miller6b05d582011-07-18 13:09:59 -070051
Jim Miller6b05d582011-07-18 13:09:59 -070052
Jim Miller1c188282011-08-08 22:27:58 -070053import com.android.internal.R;
54
55public class TransportControlView extends FrameLayout implements OnClickListener,
56 LockScreenWidgetInterface {
57
58 private static final int MSG_UPDATE_STATE = 100;
59 private static final int MSG_SET_METADATA = 101;
60 private static final int MSG_SET_TRANSPORT_CONTROLS = 102;
61 private static final int MSG_SET_ARTWORK = 103;
62 private static final int MSG_SET_GENERATION_ID = 104;
63 private static final int MAXDIM = 512;
Jean-Michel Trivi68622392011-09-19 14:53:14 -070064 private static final int DISPLAY_TIMEOUT_MS = 5000; // 5s
Jim Miller4e6d3582011-10-13 18:22:13 -070065 protected static final boolean DEBUG = false;
Jim Miller1c188282011-08-08 22:27:58 -070066 protected static final String TAG = "TransportControlView";
67
68 private ImageView mAlbumArt;
69 private TextView mTrackTitle;
70 private ImageView mBtnPrev;
71 private ImageView mBtnPlay;
72 private ImageView mBtnNext;
73 private int mClientGeneration;
74 private Metadata mMetadata = new Metadata();
75 private boolean mAttached;
Jean-Michel Trivif0cff042011-09-14 18:11:09 -070076 private PendingIntent mClientIntent;
Jim Miller1c188282011-08-08 22:27:58 -070077 private int mTransportControlFlags;
Jim Miller4e6d3582011-10-13 18:22:13 -070078 private int mCurrentPlayState;
Jim Miller1c188282011-08-08 22:27:58 -070079 private AudioManager mAudioManager;
80 private LockScreenWidgetCallback mWidgetCallbacks;
81 private IRemoteControlDisplayWeak mIRCD;
82
83 /**
84 * The metadata which should be populated into the view once we've been attached
85 */
86 private Bundle mPopulateMetadataWhenAttached = null;
87
88 // This handler is required to ensure messages from IRCD are handled in sequence and on
89 // the UI thread.
Jim Miller6b05d582011-07-18 13:09:59 -070090 private Handler mHandler = new Handler() {
Jim Miller1c188282011-08-08 22:27:58 -070091 @Override
Jim Miller6b05d582011-07-18 13:09:59 -070092 public void handleMessage(Message msg) {
Jim Miller1c188282011-08-08 22:27:58 -070093 switch (msg.what) {
94 case MSG_UPDATE_STATE:
95 if (mClientGeneration == msg.arg1) updatePlayPauseState(msg.arg2);
96 break;
97
98 case MSG_SET_METADATA:
99 if (mClientGeneration == msg.arg1) updateMetadata((Bundle) msg.obj);
100 break;
101
102 case MSG_SET_TRANSPORT_CONTROLS:
103 if (mClientGeneration == msg.arg1) updateTransportControls(msg.arg2);
104 break;
105
106 case MSG_SET_ARTWORK:
107 if (mClientGeneration == msg.arg1) {
Jean-Michel Trivi01d96bd2011-09-19 11:17:02 -0700108 if (mMetadata.bitmap != null) {
109 mMetadata.bitmap.recycle();
110 }
Jim Miller1c188282011-08-08 22:27:58 -0700111 mMetadata.bitmap = (Bitmap) msg.obj;
112 mAlbumArt.setImageBitmap(mMetadata.bitmap);
113 }
114 break;
115
116 case MSG_SET_GENERATION_ID:
Jim Miller4e6d3582011-10-13 18:22:13 -0700117 if (msg.arg2 != 0) {
Jim Millera5ff5b42011-10-19 17:36:51 -0700118 // This means nobody is currently registered. Hide the view.
119 if (mWidgetCallbacks != null) {
120 mWidgetCallbacks.requestHide(TransportControlView.this);
121 }
Jim Miller1c188282011-08-08 22:27:58 -0700122 }
Jim Miller4e6d3582011-10-13 18:22:13 -0700123 if (DEBUG) Log.v(TAG, "New genId = " + msg.arg1 + ", clearing = " + msg.arg2);
Jim Miller1c188282011-08-08 22:27:58 -0700124 mClientGeneration = msg.arg1;
Jean-Michel Trivif0cff042011-09-14 18:11:09 -0700125 mClientIntent = (PendingIntent) msg.obj;
Jim Miller1c188282011-08-08 22:27:58 -0700126 break;
127
Jim Miller6b05d582011-07-18 13:09:59 -0700128 }
129 }
130 };
131
Jim Miller1c188282011-08-08 22:27:58 -0700132 /**
133 * This class is required to have weak linkage to the current TransportControlView
134 * because the remote process can hold a strong reference to this binder object and
135 * we can't predict when it will be GC'd in the remote process. Without this code, it
136 * would allow a heavyweight object to be held on this side of the binder when there's
137 * no requirement to run a GC on the other side.
138 */
139 private static class IRemoteControlDisplayWeak extends IRemoteControlDisplay.Stub {
140 private WeakReference<Handler> mLocalHandler;
Jim Miller6b05d582011-07-18 13:09:59 -0700141
Jim Miller1c188282011-08-08 22:27:58 -0700142 IRemoteControlDisplayWeak(Handler handler) {
143 mLocalHandler = new WeakReference<Handler>(handler);
144 }
145
Jean-Michel Trivibc43b4c2013-03-22 09:30:50 -0700146 public void setPlaybackState(int generationId, int state, long stateChangeTimeMs,
147 long currentPosMs, float speed) {
Jim Miller1c188282011-08-08 22:27:58 -0700148 Handler handler = mLocalHandler.get();
149 if (handler != null) {
150 handler.obtainMessage(MSG_UPDATE_STATE, generationId, state).sendToTarget();
151 }
152 }
153
154 public void setMetadata(int generationId, Bundle metadata) {
155 Handler handler = mLocalHandler.get();
156 if (handler != null) {
157 handler.obtainMessage(MSG_SET_METADATA, generationId, 0, metadata).sendToTarget();
158 }
159 }
160
Jean-Michel Trivi3261b532013-04-01 14:59:39 -0700161 public void setTransportControlInfo(int generationId, int flags, int posCapabilities) {
Jim Miller1c188282011-08-08 22:27:58 -0700162 Handler handler = mLocalHandler.get();
163 if (handler != null) {
164 handler.obtainMessage(MSG_SET_TRANSPORT_CONTROLS, generationId, flags)
165 .sendToTarget();
166 }
167 }
168
169 public void setArtwork(int generationId, Bitmap bitmap) {
170 Handler handler = mLocalHandler.get();
171 if (handler != null) {
172 handler.obtainMessage(MSG_SET_ARTWORK, generationId, 0, bitmap).sendToTarget();
173 }
174 }
175
176 public void setAllMetadata(int generationId, Bundle metadata, Bitmap bitmap) {
177 Handler handler = mLocalHandler.get();
178 if (handler != null) {
179 handler.obtainMessage(MSG_SET_METADATA, generationId, 0, metadata).sendToTarget();
180 handler.obtainMessage(MSG_SET_ARTWORK, generationId, 0, bitmap).sendToTarget();
181 }
182 }
183
Jean-Michel Trivif0cff042011-09-14 18:11:09 -0700184 public void setCurrentClientId(int clientGeneration, PendingIntent mediaIntent,
Jim Miller1c188282011-08-08 22:27:58 -0700185 boolean clearing) throws RemoteException {
186 Handler handler = mLocalHandler.get();
187 if (handler != null) {
188 handler.obtainMessage(MSG_SET_GENERATION_ID,
Jean-Michel Trivif0cff042011-09-14 18:11:09 -0700189 clientGeneration, (clearing ? 1 : 0), mediaIntent).sendToTarget();
Jim Miller1c188282011-08-08 22:27:58 -0700190 }
191 }
192 };
Jim Miller6b05d582011-07-18 13:09:59 -0700193
194 public TransportControlView(Context context, AttributeSet attrs) {
195 super(context, attrs);
Dianne Hackborn7ff30112012-11-08 11:12:09 -0800196 if (DEBUG) Log.v(TAG, "Create TCV " + this);
Jim Miller1c188282011-08-08 22:27:58 -0700197 mAudioManager = new AudioManager(mContext);
Jim Miller4e6d3582011-10-13 18:22:13 -0700198 mCurrentPlayState = RemoteControlClient.PLAYSTATE_NONE; // until we get a callback
Jim Miller1c188282011-08-08 22:27:58 -0700199 mIRCD = new IRemoteControlDisplayWeak(mHandler);
Jim Miller6b05d582011-07-18 13:09:59 -0700200 }
201
Jim Miller1c188282011-08-08 22:27:58 -0700202 private void updateTransportControls(int transportControlFlags) {
203 mTransportControlFlags = transportControlFlags;
Jim Miller6b05d582011-07-18 13:09:59 -0700204 }
205
206 @Override
207 public void onFinishInflate() {
Jim Miller1c188282011-08-08 22:27:58 -0700208 super.onFinishInflate();
209 mTrackTitle = (TextView) findViewById(R.id.title);
210 mTrackTitle.setSelected(true); // enable marquee
211 mAlbumArt = (ImageView) findViewById(R.id.albumart);
212 mBtnPrev = (ImageView) findViewById(R.id.btn_prev);
213 mBtnPlay = (ImageView) findViewById(R.id.btn_play);
214 mBtnNext = (ImageView) findViewById(R.id.btn_next);
215 final View buttons[] = { mBtnPrev, mBtnPlay, mBtnNext };
216 for (View view : buttons) {
217 view.setOnClickListener(this);
218 }
219 }
220
221 @Override
222 public void onAttachedToWindow() {
223 super.onAttachedToWindow();
224 if (mPopulateMetadataWhenAttached != null) {
225 updateMetadata(mPopulateMetadataWhenAttached);
226 mPopulateMetadataWhenAttached = null;
227 }
228 if (!mAttached) {
229 if (DEBUG) Log.v(TAG, "Registering TCV " + this);
230 mAudioManager.registerRemoteControlDisplay(mIRCD);
231 }
232 mAttached = true;
233 }
234
235 @Override
236 public void onDetachedFromWindow() {
237 super.onDetachedFromWindow();
238 if (mAttached) {
239 if (DEBUG) Log.v(TAG, "Unregistering TCV " + this);
240 mAudioManager.unregisterRemoteControlDisplay(mIRCD);
241 }
242 mAttached = false;
243 }
244
245 @Override
246 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
247 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
248 int dim = Math.min(MAXDIM, Math.max(getWidth(), getHeight()));
249// Log.v(TAG, "setting max bitmap size: " + dim + "x" + dim);
250// mAudioManager.remoteControlDisplayUsesBitmapSize(mIRCD, dim, dim);
251 }
252
253 class Metadata {
254 private String artist;
255 private String trackTitle;
256 private String albumTitle;
257 private Bitmap bitmap;
258
259 public String toString() {
260 return "Metadata[artist=" + artist + " trackTitle=" + trackTitle + " albumTitle=" + albumTitle + "]";
261 }
262 }
263
264 private String getMdString(Bundle data, int id) {
265 return data.getString(Integer.toString(id));
266 }
267
268 private void updateMetadata(Bundle data) {
269 if (mAttached) {
270 mMetadata.artist = getMdString(data, MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST);
271 mMetadata.trackTitle = getMdString(data, MediaMetadataRetriever.METADATA_KEY_TITLE);
272 mMetadata.albumTitle = getMdString(data, MediaMetadataRetriever.METADATA_KEY_ALBUM);
273 populateMetadata();
274 } else {
275 mPopulateMetadataWhenAttached = data;
276 }
277 }
278
279 /**
280 * Populates the given metadata into the view
281 */
282 private void populateMetadata() {
283 StringBuilder sb = new StringBuilder();
284 int trackTitleLength = 0;
285 if (!TextUtils.isEmpty(mMetadata.trackTitle)) {
286 sb.append(mMetadata.trackTitle);
287 trackTitleLength = mMetadata.trackTitle.length();
288 }
289 if (!TextUtils.isEmpty(mMetadata.artist)) {
290 if (sb.length() != 0) {
291 sb.append(" - ");
292 }
293 sb.append(mMetadata.artist);
294 }
295 if (!TextUtils.isEmpty(mMetadata.albumTitle)) {
296 if (sb.length() != 0) {
297 sb.append(" - ");
298 }
299 sb.append(mMetadata.albumTitle);
300 }
301 mTrackTitle.setText(sb.toString(), TextView.BufferType.SPANNABLE);
302 Spannable str = (Spannable) mTrackTitle.getText();
303 if (trackTitleLength != 0) {
304 str.setSpan(new ForegroundColorSpan(0xffffffff), 0, trackTitleLength,
305 Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
306 trackTitleLength++;
307 }
308 if (sb.length() > trackTitleLength) {
309 str.setSpan(new ForegroundColorSpan(0x7fffffff), trackTitleLength, sb.length(),
310 Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
311 }
312
313 mAlbumArt.setImageBitmap(mMetadata.bitmap);
314 final int flags = mTransportControlFlags;
315 setVisibilityBasedOnFlag(mBtnPrev, flags, RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS);
316 setVisibilityBasedOnFlag(mBtnNext, flags, RemoteControlClient.FLAG_KEY_MEDIA_NEXT);
Jim Miller1f0eac92012-03-01 16:48:54 -0800317 setVisibilityBasedOnFlag(mBtnPlay, flags,
Jim Miller1c188282011-08-08 22:27:58 -0700318 RemoteControlClient.FLAG_KEY_MEDIA_PLAY
319 | RemoteControlClient.FLAG_KEY_MEDIA_PAUSE
320 | RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE
321 | RemoteControlClient.FLAG_KEY_MEDIA_STOP);
322
Jim Miller4e6d3582011-10-13 18:22:13 -0700323 updatePlayPauseState(mCurrentPlayState);
Jim Miller1c188282011-08-08 22:27:58 -0700324 }
325
326 private static void setVisibilityBasedOnFlag(View view, int flags, int flag) {
327 if ((flags & flag) != 0) {
328 view.setVisibility(View.VISIBLE);
329 } else {
330 view.setVisibility(View.GONE);
331 }
332 }
333
334 private void updatePlayPauseState(int state) {
335 if (DEBUG) Log.v(TAG,
Jim Miller4e6d3582011-10-13 18:22:13 -0700336 "updatePlayPauseState(), old=" + mCurrentPlayState + ", state=" + state);
337 if (state == mCurrentPlayState) {
Jim Miller1c188282011-08-08 22:27:58 -0700338 return;
339 }
Jim Miller67e043d2011-10-10 17:48:01 -0700340 final int imageResId;
341 final int imageDescId;
Jim Miller83e160d2011-10-14 11:06:33 -0700342 boolean showIfHidden = false;
Jim Miller1c188282011-08-08 22:27:58 -0700343 switch (state) {
Jean-Michel Trivi261381c2011-10-13 16:53:08 -0700344 case RemoteControlClient.PLAYSTATE_ERROR:
345 imageResId = com.android.internal.R.drawable.stat_sys_warning;
346 // TODO use more specific image description string for warning, but here the "play"
347 // message is still valid because this button triggers a play command.
348 imageDescId = com.android.internal.R.string.lockscreen_transport_play_description;
349 break;
350
Jim Miller1c188282011-08-08 22:27:58 -0700351 case RemoteControlClient.PLAYSTATE_PLAYING:
Jim Miller67e043d2011-10-10 17:48:01 -0700352 imageResId = com.android.internal.R.drawable.ic_media_pause;
353 imageDescId = com.android.internal.R.string.lockscreen_transport_pause_description;
Jim Miller4e6d3582011-10-13 18:22:13 -0700354 showIfHidden = true;
Jim Miller1c188282011-08-08 22:27:58 -0700355 break;
356
357 case RemoteControlClient.PLAYSTATE_BUFFERING:
Jim Miller67e043d2011-10-10 17:48:01 -0700358 imageResId = com.android.internal.R.drawable.ic_media_stop;
359 imageDescId = com.android.internal.R.string.lockscreen_transport_stop_description;
Jim Miller4e6d3582011-10-13 18:22:13 -0700360 showIfHidden = true;
Jim Miller1c188282011-08-08 22:27:58 -0700361 break;
362
363 case RemoteControlClient.PLAYSTATE_PAUSED:
364 default:
Jim Miller67e043d2011-10-10 17:48:01 -0700365 imageResId = com.android.internal.R.drawable.ic_media_play;
366 imageDescId = com.android.internal.R.string.lockscreen_transport_play_description;
Jim Miller4e6d3582011-10-13 18:22:13 -0700367 showIfHidden = false;
Jim Miller1c188282011-08-08 22:27:58 -0700368 break;
369 }
Jim Miller67e043d2011-10-10 17:48:01 -0700370 mBtnPlay.setImageResource(imageResId);
371 mBtnPlay.setContentDescription(getResources().getString(imageDescId));
Jim Miller4e6d3582011-10-13 18:22:13 -0700372 if (showIfHidden && mWidgetCallbacks != null && !mWidgetCallbacks.isVisible(this)) {
373 mWidgetCallbacks.requestShow(this);
374 }
375 mCurrentPlayState = state;
376 }
377
378 static class SavedState extends BaseSavedState {
379 boolean wasShowing;
380
381 SavedState(Parcelable superState) {
382 super(superState);
383 }
384
385 private SavedState(Parcel in) {
386 super(in);
387 this.wasShowing = in.readInt() != 0;
388 }
389
390 @Override
391 public void writeToParcel(Parcel out, int flags) {
392 super.writeToParcel(out, flags);
393 out.writeInt(this.wasShowing ? 1 : 0);
394 }
395
396 public static final Parcelable.Creator<SavedState> CREATOR
397 = new Parcelable.Creator<SavedState>() {
398 public SavedState createFromParcel(Parcel in) {
399 return new SavedState(in);
400 }
401
402 public SavedState[] newArray(int size) {
403 return new SavedState[size];
404 }
405 };
406 }
407
408 @Override
409 public Parcelable onSaveInstanceState() {
410 if (DEBUG) Log.v(TAG, "onSaveInstanceState()");
411 Parcelable superState = super.onSaveInstanceState();
412 SavedState ss = new SavedState(superState);
Jim Millera5ff5b42011-10-19 17:36:51 -0700413 ss.wasShowing = mWidgetCallbacks != null && mWidgetCallbacks.isVisible(this);
Jim Miller4e6d3582011-10-13 18:22:13 -0700414 return ss;
415 }
416
417 @Override
418 public void onRestoreInstanceState(Parcelable state) {
419 if (DEBUG) Log.v(TAG, "onRestoreInstanceState()");
420 if (!(state instanceof SavedState)) {
421 super.onRestoreInstanceState(state);
422 return;
423 }
424 SavedState ss = (SavedState) state;
425 super.onRestoreInstanceState(ss.getSuperState());
Jim Millera5ff5b42011-10-19 17:36:51 -0700426 if (ss.wasShowing && mWidgetCallbacks != null) {
Jim Miller4e6d3582011-10-13 18:22:13 -0700427 mWidgetCallbacks.requestShow(this);
428 }
Jim Miller1c188282011-08-08 22:27:58 -0700429 }
430
431 public void onClick(View v) {
432 int keyCode = -1;
433 if (v == mBtnPrev) {
434 keyCode = KeyEvent.KEYCODE_MEDIA_PREVIOUS;
435 } else if (v == mBtnNext) {
436 keyCode = KeyEvent.KEYCODE_MEDIA_NEXT;
437 } else if (v == mBtnPlay) {
438 keyCode = KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE;
439
440 }
441 if (keyCode != -1) {
442 sendMediaButtonClick(keyCode);
443 if (mWidgetCallbacks != null) {
444 mWidgetCallbacks.userActivity(this);
Jim Miller6b05d582011-07-18 13:09:59 -0700445 }
446 }
447 }
448
Jim Miller1c188282011-08-08 22:27:58 -0700449 private void sendMediaButtonClick(int keyCode) {
Jim Millera5ff5b42011-10-19 17:36:51 -0700450 if (mClientIntent == null) {
451 // Shouldn't be possible because this view should be hidden in this case.
452 Log.e(TAG, "sendMediaButtonClick(): No client is currently registered");
453 return;
454 }
Jean-Michel Trivif0cff042011-09-14 18:11:09 -0700455 // use the registered PendingIntent that will be processed by the registered
456 // media button event receiver, which is the component of mClientIntent
Jim Miller1c188282011-08-08 22:27:58 -0700457 KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
458 Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
459 intent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
Jean-Michel Trivif0cff042011-09-14 18:11:09 -0700460 try {
461 mClientIntent.send(getContext(), 0, intent);
462 } catch (CanceledException e) {
463 Log.e(TAG, "Error sending intent for media button down: "+e);
464 e.printStackTrace();
465 }
Jim Miller6b05d582011-07-18 13:09:59 -0700466
Jim Miller1c188282011-08-08 22:27:58 -0700467 keyEvent = new KeyEvent(KeyEvent.ACTION_UP, keyCode);
468 intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
469 intent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
Jean-Michel Trivif0cff042011-09-14 18:11:09 -0700470 try {
471 mClientIntent.send(getContext(), 0, intent);
472 } catch (CanceledException e) {
473 Log.e(TAG, "Error sending intent for media button up: "+e);
474 e.printStackTrace();
475 }
Jim Miller1c188282011-08-08 22:27:58 -0700476 }
Jim Miller6b05d582011-07-18 13:09:59 -0700477
Jim Miller1c188282011-08-08 22:27:58 -0700478 public void setCallback(LockScreenWidgetCallback callback) {
479 mWidgetCallbacks = callback;
Jim Miller6b05d582011-07-18 13:09:59 -0700480 }
481
Jeff Sharkey054340d2011-09-01 22:28:03 -0700482 public boolean providesClock() {
483 return false;
484 }
485
Jean-Michel Trivi68622392011-09-19 14:53:14 -0700486 private boolean wasPlayingRecently(int state, long stateChangeTimeMs) {
487 switch (state) {
488 case RemoteControlClient.PLAYSTATE_PLAYING:
489 case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
490 case RemoteControlClient.PLAYSTATE_REWINDING:
491 case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
492 case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
493 case RemoteControlClient.PLAYSTATE_BUFFERING:
494 // actively playing or about to play
495 return true;
496 case RemoteControlClient.PLAYSTATE_NONE:
497 return false;
498 case RemoteControlClient.PLAYSTATE_STOPPED:
499 case RemoteControlClient.PLAYSTATE_PAUSED:
500 case RemoteControlClient.PLAYSTATE_ERROR:
501 // we have stopped playing, check how long ago
502 if (DEBUG) {
503 if ((SystemClock.elapsedRealtime() - stateChangeTimeMs) < DISPLAY_TIMEOUT_MS) {
504 Log.v(TAG, "wasPlayingRecently: time < TIMEOUT was playing recently");
505 } else {
506 Log.v(TAG, "wasPlayingRecently: time > TIMEOUT");
507 }
508 }
509 return ((SystemClock.elapsedRealtime() - stateChangeTimeMs) < DISPLAY_TIMEOUT_MS);
510 default:
511 Log.e(TAG, "Unknown playback state " + state + " in wasPlayingRecently()");
512 return false;
513 }
514 }
Jim Miller6b05d582011-07-18 13:09:59 -0700515}