blob: 490317b188c2d6f26f9c03f69556a82c3423add3 [file] [log] [blame]
Eliot Courtney09322282017-11-09 15:31:19 +09001/*
2 * Copyright (C) 2017 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 */
Eliot Courtney3ebbccd2017-11-08 09:59:38 +090016package com.android.systemui.statusbar;
17
Jason Monk297c04e2018-08-23 17:16:59 -040018import static com.android.systemui.Dependency.MAIN_HANDLER;
19import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
20import static com.android.systemui.statusbar.phone.StatusBar.DEBUG_MEDIA_FAKE_ARTWORK;
21import static com.android.systemui.statusbar.phone.StatusBar.ENABLE_LOCKSCREEN_WALLPAPER;
22import static com.android.systemui.statusbar.phone.StatusBar.SHOW_LOCKSCREEN_MEDIA_ARTWORK;
23
24import android.annotation.Nullable;
Eliot Courtney3ebbccd2017-11-08 09:59:38 +090025import android.app.Notification;
26import android.content.Context;
Jason Monk297c04e2018-08-23 17:16:59 -040027import android.graphics.Bitmap;
Lucas Dupinba57b4a2019-01-21 14:55:57 -080028import android.graphics.Color;
Jason Monk297c04e2018-08-23 17:16:59 -040029import android.graphics.drawable.BitmapDrawable;
30import android.graphics.drawable.ColorDrawable;
31import android.graphics.drawable.Drawable;
Lucas Dupin6a03a9f2018-12-20 17:13:52 -080032import android.graphics.drawable.Icon;
Eliot Courtney3ebbccd2017-11-08 09:59:38 +090033import android.media.MediaMetadata;
34import android.media.session.MediaController;
35import android.media.session.MediaSession;
36import android.media.session.MediaSessionManager;
37import android.media.session.PlaybackState;
Jason Monk297c04e2018-08-23 17:16:59 -040038import android.os.Handler;
39import android.os.Trace;
Eliot Courtney3ebbccd2017-11-08 09:59:38 +090040import android.os.UserHandle;
41import android.util.Log;
Jason Monk297c04e2018-08-23 17:16:59 -040042import android.view.View;
43import android.widget.ImageView;
Eliot Courtney3ebbccd2017-11-08 09:59:38 +090044
Gus Prevasca1b6f72018-12-28 10:53:11 -050045import com.android.internal.statusbar.NotificationVisibility;
Jason Monk297c04e2018-08-23 17:16:59 -040046import com.android.systemui.Dependency;
Eliot Courtney3ebbccd2017-11-08 09:59:38 +090047import com.android.systemui.Dumpable;
Jason Monk297c04e2018-08-23 17:16:59 -040048import com.android.systemui.Interpolators;
49import com.android.systemui.colorextraction.SysuiColorExtractor;
Beverly8fdb5332019-02-04 14:29:49 -050050import com.android.systemui.plugins.statusbar.StatusBarStateController;
Gus Prevas2d5a1e92018-12-21 15:36:06 -050051import com.android.systemui.statusbar.notification.NotificationEntryListener;
Rohan Shah20790b82018-07-02 17:21:04 -070052import com.android.systemui.statusbar.notification.NotificationEntryManager;
Ned Burnsf81c4c42019-01-07 14:10:43 -050053import com.android.systemui.statusbar.notification.collection.NotificationEntry;
Jason Monk297c04e2018-08-23 17:16:59 -040054import com.android.systemui.statusbar.phone.BiometricUnlockController;
55import com.android.systemui.statusbar.phone.LockscreenWallpaper;
56import com.android.systemui.statusbar.phone.ScrimController;
57import com.android.systemui.statusbar.phone.ScrimState;
58import com.android.systemui.statusbar.phone.ShadeController;
59import com.android.systemui.statusbar.phone.StatusBarWindowController;
60import com.android.systemui.statusbar.policy.KeyguardMonitor;
Eliot Courtney3ebbccd2017-11-08 09:59:38 +090061
62import java.io.FileDescriptor;
63import java.io.PrintWriter;
64import java.util.ArrayList;
65import java.util.List;
66
Jason Monk27d01a622018-12-10 15:57:09 -050067import javax.inject.Inject;
68import javax.inject.Singleton;
69
Gus Prevas2d5a1e92018-12-21 15:36:06 -050070import dagger.Lazy;
71
Eliot Courtney3ebbccd2017-11-08 09:59:38 +090072/**
73 * Handles tasks and state related to media notifications. For example, there is a 'current' media
74 * notification, which this class keeps track of.
75 */
Jason Monk27d01a622018-12-10 15:57:09 -050076@Singleton
Eliot Courtney3ebbccd2017-11-08 09:59:38 +090077public class NotificationMediaManager implements Dumpable {
78 private static final String TAG = "NotificationMediaManager";
79 public static final boolean DEBUG_MEDIA = false;
80
Jason Monk297c04e2018-08-23 17:16:59 -040081 private final StatusBarStateController mStatusBarStateController
82 = Dependency.get(StatusBarStateController.class);
83 private final SysuiColorExtractor mColorExtractor = Dependency.get(SysuiColorExtractor.class);
84 private final KeyguardMonitor mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
85
86 // Late binding
87 private NotificationEntryManager mEntryManager;
88
89 // Late binding, also @Nullable due to being in com.android.systemui.statusbar.phone package
90 @Nullable
Gus Prevas2d5a1e92018-12-21 15:36:06 -050091 private Lazy<ShadeController> mShadeController;
Jason Monk297c04e2018-08-23 17:16:59 -040092 @Nullable
Gus Prevas2d5a1e92018-12-21 15:36:06 -050093 private Lazy<StatusBarWindowController> mStatusBarWindowController;
Jason Monk297c04e2018-08-23 17:16:59 -040094
95 @Nullable
96 private BiometricUnlockController mBiometricUnlockController;
97 @Nullable
98 private ScrimController mScrimController;
99 @Nullable
100 private LockscreenWallpaper mLockscreenWallpaper;
101
Jason Monk297c04e2018-08-23 17:16:59 -0400102 private final Handler mHandler = Dependency.get(MAIN_HANDLER);
103
Eliot Courtney3ebbccd2017-11-08 09:59:38 +0900104 private final Context mContext;
105 private final MediaSessionManager mMediaSessionManager;
Lucas Dupin6a03a9f2018-12-20 17:13:52 -0800106 private final ArrayList<MediaListener> mMediaListeners;
Lucas Dupinba57b4a2019-01-21 14:55:57 -0800107 private final MediaArtworkProcessor mMediaArtworkProcessor;
Eliot Courtneya6d8cf22017-10-20 13:26:58 +0900108
Eliot Courtney4a96b362017-12-14 19:38:52 +0900109 protected NotificationPresenter mPresenter;
Eliot Courtney3ebbccd2017-11-08 09:59:38 +0900110 private MediaController mMediaController;
111 private String mMediaNotificationKey;
112 private MediaMetadata mMediaMetadata;
113
Jason Monk297c04e2018-08-23 17:16:59 -0400114 private BackDropView mBackdrop;
115 private ImageView mBackdropFront;
116 private ImageView mBackdropBack;
117
Eliot Courtney3ebbccd2017-11-08 09:59:38 +0900118 private final MediaController.Callback mMediaListener = new MediaController.Callback() {
119 @Override
120 public void onPlaybackStateChanged(PlaybackState state) {
121 super.onPlaybackStateChanged(state);
122 if (DEBUG_MEDIA) {
123 Log.v(TAG, "DEBUG_MEDIA: onPlaybackStateChanged: " + state);
124 }
125 if (state != null) {
126 if (!isPlaybackActive(state.getState())) {
127 clearCurrentMediaNotification();
Lucas Dupin6a03a9f2018-12-20 17:13:52 -0800128 dispatchUpdateMediaMetaData(true /* changed */, true /* allowAnimation */);
Eliot Courtney3ebbccd2017-11-08 09:59:38 +0900129 }
130 }
131 }
132
133 @Override
134 public void onMetadataChanged(MediaMetadata metadata) {
135 super.onMetadataChanged(metadata);
136 if (DEBUG_MEDIA) {
137 Log.v(TAG, "DEBUG_MEDIA: onMetadataChanged: " + metadata);
138 }
Lucas Dupinba57b4a2019-01-21 14:55:57 -0800139 mMediaArtworkProcessor.clearCache();
Eliot Courtney3ebbccd2017-11-08 09:59:38 +0900140 mMediaMetadata = metadata;
Lucas Dupin6a03a9f2018-12-20 17:13:52 -0800141 dispatchUpdateMediaMetaData(true /* changed */, true /* allowAnimation */);
Eliot Courtney3ebbccd2017-11-08 09:59:38 +0900142 }
143 };
144
Jason Monk27d01a622018-12-10 15:57:09 -0500145 @Inject
Gus Prevas2d5a1e92018-12-21 15:36:06 -0500146 public NotificationMediaManager(
147 Context context,
148 Lazy<ShadeController> shadeController,
149 Lazy<StatusBarWindowController> statusBarWindowController,
Lucas Dupinba57b4a2019-01-21 14:55:57 -0800150 NotificationEntryManager notificationEntryManager,
151 MediaArtworkProcessor mediaArtworkProcessor) {
Eliot Courtney3ebbccd2017-11-08 09:59:38 +0900152 mContext = context;
Lucas Dupinba57b4a2019-01-21 14:55:57 -0800153 mMediaArtworkProcessor = mediaArtworkProcessor;
Lucas Dupin6a03a9f2018-12-20 17:13:52 -0800154 mMediaListeners = new ArrayList<>();
Eliot Courtney3ebbccd2017-11-08 09:59:38 +0900155 mMediaSessionManager
156 = (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
157 // TODO: use MediaSessionManager.SessionListener to hook us up to future updates
158 // in session state
Gus Prevas2d5a1e92018-12-21 15:36:06 -0500159 mShadeController = shadeController;
160 mStatusBarWindowController = statusBarWindowController;
161 mEntryManager = notificationEntryManager;
162 notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
163 @Override
Gus Prevas772e5322018-12-21 16:22:16 -0500164 public void onEntryRemoved(
Ned Burnsf81c4c42019-01-07 14:10:43 -0500165 NotificationEntry entry,
Gus Prevasca1b6f72018-12-28 10:53:11 -0500166 NotificationVisibility visibility,
Gus Prevas772e5322018-12-21 16:22:16 -0500167 boolean removedByUser) {
Ned Burnsef2ef6c2019-01-02 16:48:08 -0500168 onNotificationRemoved(entry.key);
Gus Prevas2d5a1e92018-12-21 15:36:06 -0500169 }
170 });
Eliot Courtney3ebbccd2017-11-08 09:59:38 +0900171 }
172
Jason Monk297c04e2018-08-23 17:16:59 -0400173 public void setUpWithPresenter(NotificationPresenter presenter) {
Eliot Courtneya6d8cf22017-10-20 13:26:58 +0900174 mPresenter = presenter;
175 }
176
Eliot Courtney3ebbccd2017-11-08 09:59:38 +0900177 public void onNotificationRemoved(String key) {
178 if (key.equals(mMediaNotificationKey)) {
179 clearCurrentMediaNotification();
Lucas Dupin6a03a9f2018-12-20 17:13:52 -0800180 dispatchUpdateMediaMetaData(true /* changed */, true /* allowEnterAnimation */);
Eliot Courtney3ebbccd2017-11-08 09:59:38 +0900181 }
182 }
183
184 public String getMediaNotificationKey() {
185 return mMediaNotificationKey;
186 }
187
188 public MediaMetadata getMediaMetadata() {
189 return mMediaMetadata;
190 }
191
Lucas Dupin6a03a9f2018-12-20 17:13:52 -0800192 public Icon getMediaIcon() {
193 if (mMediaNotificationKey == null) {
194 return null;
195 }
Gus Prevas2d5a1e92018-12-21 15:36:06 -0500196 synchronized (mEntryManager.getNotificationData()) {
Ned Burnsf81c4c42019-01-07 14:10:43 -0500197 NotificationEntry entry = mEntryManager.getNotificationData().get(mMediaNotificationKey);
Lucas Dupin6a03a9f2018-12-20 17:13:52 -0800198 if (entry == null || entry.expandedIcon == null) {
199 return null;
200 }
201
202 return entry.expandedIcon.getSourceIcon();
203 }
204 }
205
206 public void addCallback(MediaListener callback) {
207 mMediaListeners.add(callback);
208 callback.onMetadataChanged(mMediaMetadata);
209 }
210
211 public void removeCallback(MediaListener callback) {
212 mMediaListeners.remove(callback);
213 }
214
Eliot Courtney3ebbccd2017-11-08 09:59:38 +0900215 public void findAndUpdateMediaNotifications() {
216 boolean metaDataChanged = false;
217
Gus Prevas2d5a1e92018-12-21 15:36:06 -0500218 synchronized (mEntryManager.getNotificationData()) {
Ned Burnsf81c4c42019-01-07 14:10:43 -0500219 ArrayList<NotificationEntry> activeNotifications =
Gus Prevas2d5a1e92018-12-21 15:36:06 -0500220 mEntryManager.getNotificationData().getActiveNotifications();
Eliot Courtney3ebbccd2017-11-08 09:59:38 +0900221 final int N = activeNotifications.size();
222
223 // Promote the media notification with a controller in 'playing' state, if any.
Ned Burnsf81c4c42019-01-07 14:10:43 -0500224 NotificationEntry mediaNotification = null;
Eliot Courtney3ebbccd2017-11-08 09:59:38 +0900225 MediaController controller = null;
226 for (int i = 0; i < N; i++) {
Ned Burnsf81c4c42019-01-07 14:10:43 -0500227 final NotificationEntry entry = activeNotifications.get(i);
Eliot Courtney3ebbccd2017-11-08 09:59:38 +0900228
Evan Laird94492852018-10-25 13:43:01 -0400229 if (entry.isMediaNotification()) {
Eliot Courtney3ebbccd2017-11-08 09:59:38 +0900230 final MediaSession.Token token =
231 entry.notification.getNotification().extras.getParcelable(
232 Notification.EXTRA_MEDIA_SESSION);
233 if (token != null) {
234 MediaController aController = new MediaController(mContext, token);
235 if (PlaybackState.STATE_PLAYING ==
236 getMediaControllerPlaybackState(aController)) {
237 if (DEBUG_MEDIA) {
238 Log.v(TAG, "DEBUG_MEDIA: found mediastyle controller matching "
239 + entry.notification.getKey());
240 }
241 mediaNotification = entry;
242 controller = aController;
243 break;
244 }
245 }
246 }
247 }
248 if (mediaNotification == null) {
249 // Still nothing? OK, let's just look for live media sessions and see if they match
250 // one of our notifications. This will catch apps that aren't (yet!) using media
251 // notifications.
252
253 if (mMediaSessionManager != null) {
254 // TODO: Should this really be for all users?
255 final List<MediaController> sessions
256 = mMediaSessionManager.getActiveSessionsForUser(
257 null,
258 UserHandle.USER_ALL);
259
260 for (MediaController aController : sessions) {
261 if (PlaybackState.STATE_PLAYING ==
262 getMediaControllerPlaybackState(aController)) {
263 // now to see if we have one like this
264 final String pkg = aController.getPackageName();
265
266 for (int i = 0; i < N; i++) {
Ned Burnsf81c4c42019-01-07 14:10:43 -0500267 final NotificationEntry entry = activeNotifications.get(i);
Eliot Courtney3ebbccd2017-11-08 09:59:38 +0900268 if (entry.notification.getPackageName().equals(pkg)) {
269 if (DEBUG_MEDIA) {
270 Log.v(TAG, "DEBUG_MEDIA: found controller matching "
271 + entry.notification.getKey());
272 }
273 controller = aController;
274 mediaNotification = entry;
275 break;
276 }
277 }
278 }
279 }
280 }
281 }
282
283 if (controller != null && !sameSessions(mMediaController, controller)) {
284 // We have a new media session
shawnlin87eae9b2018-04-20 21:42:42 +0800285 clearCurrentMediaNotificationSession();
Eliot Courtney3ebbccd2017-11-08 09:59:38 +0900286 mMediaController = controller;
287 mMediaController.registerCallback(mMediaListener);
288 mMediaMetadata = mMediaController.getMetadata();
289 if (DEBUG_MEDIA) {
shawnlin87eae9b2018-04-20 21:42:42 +0800290 Log.v(TAG, "DEBUG_MEDIA: insert listener, found new controller: "
291 + mMediaController + ", receive metadata: " + mMediaMetadata);
Eliot Courtney3ebbccd2017-11-08 09:59:38 +0900292 }
293
Eliot Courtney3ebbccd2017-11-08 09:59:38 +0900294 metaDataChanged = true;
295 }
shawnlin87eae9b2018-04-20 21:42:42 +0800296
297 if (mediaNotification != null
298 && !mediaNotification.notification.getKey().equals(mMediaNotificationKey)) {
299 mMediaNotificationKey = mediaNotification.notification.getKey();
300 if (DEBUG_MEDIA) {
301 Log.v(TAG, "DEBUG_MEDIA: Found new media notification: key="
302 + mMediaNotificationKey);
303 }
304 }
Eliot Courtney3ebbccd2017-11-08 09:59:38 +0900305 }
306
307 if (metaDataChanged) {
Gus Prevas2d5a1e92018-12-21 15:36:06 -0500308 mEntryManager.updateNotifications();
Eliot Courtney3ebbccd2017-11-08 09:59:38 +0900309 }
Evan Lairdf0348b12018-11-12 15:26:34 -0500310
Lucas Dupin6a03a9f2018-12-20 17:13:52 -0800311 dispatchUpdateMediaMetaData(metaDataChanged, true /* allowEnterAnimation */);
Eliot Courtney3ebbccd2017-11-08 09:59:38 +0900312 }
313
314 public void clearCurrentMediaNotification() {
315 mMediaNotificationKey = null;
shawnlin87eae9b2018-04-20 21:42:42 +0800316 clearCurrentMediaNotificationSession();
Eliot Courtney3ebbccd2017-11-08 09:59:38 +0900317 }
318
Lucas Dupin6a03a9f2018-12-20 17:13:52 -0800319 private void dispatchUpdateMediaMetaData(boolean changed, boolean allowEnterAnimation) {
320 if (mPresenter != null) {
321 mPresenter.updateMediaMetaData(changed, allowEnterAnimation);
322 }
323 ArrayList<MediaListener> callbacks = new ArrayList<>(mMediaListeners);
324 for (int i = 0; i < callbacks.size(); i++) {
325 callbacks.get(i).onMetadataChanged(mMediaMetadata);
326 }
327 }
328
Eliot Courtney3ebbccd2017-11-08 09:59:38 +0900329 @Override
330 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
331 pw.print(" mMediaSessionManager=");
332 pw.println(mMediaSessionManager);
333 pw.print(" mMediaNotificationKey=");
334 pw.println(mMediaNotificationKey);
335 pw.print(" mMediaController=");
336 pw.print(mMediaController);
337 if (mMediaController != null) {
338 pw.print(" state=" + mMediaController.getPlaybackState());
339 }
340 pw.println();
341 pw.print(" mMediaMetadata=");
342 pw.print(mMediaMetadata);
343 if (mMediaMetadata != null) {
344 pw.print(" title=" + mMediaMetadata.getText(MediaMetadata.METADATA_KEY_TITLE));
345 }
346 pw.println();
347 }
348
349 private boolean isPlaybackActive(int state) {
350 return state != PlaybackState.STATE_STOPPED && state != PlaybackState.STATE_ERROR
351 && state != PlaybackState.STATE_NONE;
352 }
353
354 private boolean sameSessions(MediaController a, MediaController b) {
355 if (a == b) {
356 return true;
357 }
358 if (a == null) {
359 return false;
360 }
361 return a.controlsSameSession(b);
362 }
363
364 private int getMediaControllerPlaybackState(MediaController controller) {
365 if (controller != null) {
366 final PlaybackState playbackState = controller.getPlaybackState();
367 if (playbackState != null) {
368 return playbackState.getState();
369 }
370 }
371 return PlaybackState.STATE_NONE;
372 }
373
shawnlin87eae9b2018-04-20 21:42:42 +0800374 private void clearCurrentMediaNotificationSession() {
Lucas Dupinba57b4a2019-01-21 14:55:57 -0800375 mMediaArtworkProcessor.clearCache();
shawnlin87eae9b2018-04-20 21:42:42 +0800376 mMediaMetadata = null;
377 if (mMediaController != null) {
378 if (DEBUG_MEDIA) {
379 Log.v(TAG, "DEBUG_MEDIA: Disconnecting from old controller: "
380 + mMediaController.getPackageName());
381 }
382 mMediaController.unregisterCallback(mMediaListener);
383 }
384 mMediaController = null;
385 }
Jason Monk297c04e2018-08-23 17:16:59 -0400386
387 /**
388 * Refresh or remove lockscreen artwork from media metadata or the lockscreen wallpaper.
389 */
390 public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) {
391 Trace.beginSection("StatusBar#updateMediaMetaData");
392 if (!SHOW_LOCKSCREEN_MEDIA_ARTWORK) {
393 Trace.endSection();
394 return;
395 }
396
397 if (mBackdrop == null) {
398 Trace.endSection();
399 return; // called too early
400 }
401
402 boolean wakeAndUnlock = mBiometricUnlockController != null
403 && mBiometricUnlockController.isWakeAndUnlock();
404 if (mKeyguardMonitor.isLaunchTransitionFadingAway() || wakeAndUnlock) {
405 mBackdrop.setVisibility(View.INVISIBLE);
406 Trace.endSection();
407 return;
408 }
409
410 MediaMetadata mediaMetadata = getMediaMetadata();
411
412 if (DEBUG_MEDIA) {
413 Log.v(TAG, "DEBUG_MEDIA: updating album art for notification "
414 + getMediaNotificationKey()
415 + " metadata=" + mediaMetadata
416 + " metaDataChanged=" + metaDataChanged
417 + " state=" + mStatusBarStateController.getState());
418 }
419
420 Drawable artworkDrawable = null;
421 if (mediaMetadata != null) {
422 Bitmap artworkBitmap = mediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ART);
423 if (artworkBitmap == null) {
424 artworkBitmap = mediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
425 // might still be null
426 }
427 if (artworkBitmap != null) {
Lucas Dupinba57b4a2019-01-21 14:55:57 -0800428 int notificationColor;
429 synchronized (mEntryManager.getNotificationData()) {
430 NotificationEntry entry = mEntryManager.getNotificationData()
431 .get(mMediaNotificationKey);
432 if (entry == null || entry.getRow() == null) {
433 notificationColor = Color.TRANSPARENT;
434 } else {
435 notificationColor = entry.getRow().calculateBgColor();
436 }
437 }
438 Bitmap bmp = mMediaArtworkProcessor.processArtwork(mContext, artworkBitmap,
439 notificationColor);
440 artworkDrawable = new BitmapDrawable(mBackdropBack.getResources(), bmp);
Jason Monk297c04e2018-08-23 17:16:59 -0400441 }
442 }
443 boolean allowWhenShade = false;
444 if (ENABLE_LOCKSCREEN_WALLPAPER && artworkDrawable == null) {
445 Bitmap lockWallpaper =
446 mLockscreenWallpaper != null ? mLockscreenWallpaper.getBitmap() : null;
447 if (lockWallpaper != null) {
448 artworkDrawable = new LockscreenWallpaper.WallpaperDrawable(
449 mBackdropBack.getResources(), lockWallpaper);
450 // We're in the SHADE mode on the SIM screen - yet we still need to show
451 // the lockscreen wallpaper in that mode.
452 allowWhenShade = mStatusBarStateController.getState() == KEYGUARD;
453 }
454 }
455
Gus Prevas2d5a1e92018-12-21 15:36:06 -0500456 ShadeController shadeController = mShadeController.get();
457 StatusBarWindowController windowController = mStatusBarWindowController.get();
458 boolean hideBecauseOccluded = shadeController != null && shadeController.isOccluded();
Jason Monk297c04e2018-08-23 17:16:59 -0400459
460 final boolean hasArtwork = artworkDrawable != null;
461 mColorExtractor.setHasBackdrop(hasArtwork);
462 if (mScrimController != null) {
463 mScrimController.setHasBackdrop(hasArtwork);
464 }
465
466 if ((hasArtwork || DEBUG_MEDIA_FAKE_ARTWORK)
467 && (mStatusBarStateController.getState() != StatusBarState.SHADE || allowWhenShade)
468 && mBiometricUnlockController != null && mBiometricUnlockController.getMode()
469 != BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
470 && !hideBecauseOccluded) {
471 // time to show some art!
472 if (mBackdrop.getVisibility() != View.VISIBLE) {
473 mBackdrop.setVisibility(View.VISIBLE);
474 if (allowEnterAnimation) {
475 mBackdrop.setAlpha(0);
476 mBackdrop.animate().alpha(1f);
477 } else {
478 mBackdrop.animate().cancel();
479 mBackdrop.setAlpha(1f);
480 }
Gus Prevas2d5a1e92018-12-21 15:36:06 -0500481 if (windowController != null) {
482 windowController.setBackdropShowing(true);
Jason Monk297c04e2018-08-23 17:16:59 -0400483 }
484 metaDataChanged = true;
485 if (DEBUG_MEDIA) {
486 Log.v(TAG, "DEBUG_MEDIA: Fading in album artwork");
487 }
488 }
489 if (metaDataChanged) {
490 if (mBackdropBack.getDrawable() != null) {
491 Drawable drawable =
492 mBackdropBack.getDrawable().getConstantState()
493 .newDrawable(mBackdropFront.getResources()).mutate();
494 mBackdropFront.setImageDrawable(drawable);
495 mBackdropFront.setAlpha(1f);
496 mBackdropFront.setVisibility(View.VISIBLE);
497 } else {
498 mBackdropFront.setVisibility(View.INVISIBLE);
499 }
500
501 if (DEBUG_MEDIA_FAKE_ARTWORK) {
502 final int c = 0xFF000000 | (int)(Math.random() * 0xFFFFFF);
503 Log.v(TAG, String.format("DEBUG_MEDIA: setting new color: 0x%08x", c));
504 mBackdropBack.setBackgroundColor(0xFFFFFFFF);
505 mBackdropBack.setImageDrawable(new ColorDrawable(c));
506 } else {
507 mBackdropBack.setImageDrawable(artworkDrawable);
508 }
509
510 if (mBackdropFront.getVisibility() == View.VISIBLE) {
511 if (DEBUG_MEDIA) {
512 Log.v(TAG, "DEBUG_MEDIA: Crossfading album artwork from "
513 + mBackdropFront.getDrawable()
514 + " to "
515 + mBackdropBack.getDrawable());
516 }
517 mBackdropFront.animate()
518 .setDuration(250)
519 .alpha(0f).withEndAction(mHideBackdropFront);
520 }
521 }
522 } else {
523 // need to hide the album art, either because we are unlocked, on AOD
524 // or because the metadata isn't there to support it
525 if (mBackdrop.getVisibility() != View.GONE) {
526 if (DEBUG_MEDIA) {
527 Log.v(TAG, "DEBUG_MEDIA: Fading out album artwork");
528 }
Gus Prevas2d5a1e92018-12-21 15:36:06 -0500529 boolean cannotAnimateDoze = shadeController != null
530 && shadeController.isDozing()
Jason Monk297c04e2018-08-23 17:16:59 -0400531 && !ScrimState.AOD.getAnimateChange();
532 if (mBiometricUnlockController != null && mBiometricUnlockController.getMode()
533 == BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
534 || hideBecauseOccluded || cannotAnimateDoze) {
535
536 // We are unlocking directly - no animation!
537 mBackdrop.setVisibility(View.GONE);
538 mBackdropBack.setImageDrawable(null);
Gus Prevas2d5a1e92018-12-21 15:36:06 -0500539 if (windowController != null) {
540 windowController.setBackdropShowing(false);
Jason Monk297c04e2018-08-23 17:16:59 -0400541 }
542 } else {
Gus Prevas2d5a1e92018-12-21 15:36:06 -0500543 if (windowController != null) {
544 windowController.setBackdropShowing(false);
Jason Monk297c04e2018-08-23 17:16:59 -0400545 }
546 mBackdrop.animate()
547 .alpha(0)
548 .setInterpolator(Interpolators.ACCELERATE_DECELERATE)
549 .setDuration(300)
550 .setStartDelay(0)
551 .withEndAction(() -> {
552 mBackdrop.setVisibility(View.GONE);
553 mBackdropFront.animate().cancel();
554 mBackdropBack.setImageDrawable(null);
555 mHandler.post(mHideBackdropFront);
556 });
557 if (mKeyguardMonitor.isKeyguardFadingAway()) {
558 mBackdrop.animate()
559 // Make it disappear faster, as the focus should be on the activity
560 // behind.
561 .setDuration(mKeyguardMonitor.getKeyguardFadingAwayDuration() / 2)
562 .setStartDelay(mKeyguardMonitor.getKeyguardFadingAwayDelay())
563 .setInterpolator(Interpolators.LINEAR)
564 .start();
565 }
566 }
567 }
568 }
569 Trace.endSection();
570 }
571
572 public void setup(BackDropView backdrop, ImageView backdropFront, ImageView backdropBack,
Evan Laird0c29baf2018-10-24 18:17:58 -0400573 ScrimController scrimController, LockscreenWallpaper lockscreenWallpaper) {
Jason Monk297c04e2018-08-23 17:16:59 -0400574 mBackdrop = backdrop;
575 mBackdropFront = backdropFront;
576 mBackdropBack = backdropBack;
Jason Monk297c04e2018-08-23 17:16:59 -0400577 mScrimController = scrimController;
578 mLockscreenWallpaper = lockscreenWallpaper;
579 }
580
Evan Laird0c29baf2018-10-24 18:17:58 -0400581 public void setBiometricUnlockController(BiometricUnlockController biometricUnlockController) {
582 mBiometricUnlockController = biometricUnlockController;
583 }
584
Jason Monk297c04e2018-08-23 17:16:59 -0400585 /**
586 * Hide the album artwork that is fading out and release its bitmap.
587 */
588 protected final Runnable mHideBackdropFront = new Runnable() {
589 @Override
590 public void run() {
591 if (DEBUG_MEDIA) {
592 Log.v(TAG, "DEBUG_MEDIA: removing fade layer");
593 }
594 mBackdropFront.setVisibility(View.INVISIBLE);
595 mBackdropFront.animate().cancel();
596 mBackdropFront.setImageDrawable(null);
597 }
598 };
Lucas Dupin6a03a9f2018-12-20 17:13:52 -0800599
600 public interface MediaListener {
601 void onMetadataChanged(MediaMetadata metadata);
602 }
Eliot Courtney3ebbccd2017-11-08 09:59:38 +0900603}