diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index cc8310a30ddad..a205fcf9520b6 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -42,6 +42,7 @@
- @string/status_bar_phone_evdo_signal
- @string/status_bar_phone_signal
- @string/status_bar_secure
+ - @string/status_bar_media
- @string/status_bar_managed_profile
- @string/status_bar_cast
- @string/status_bar_screen_record
@@ -96,6 +97,7 @@
airplane
sensors_off
screen_record
+ media
diff --git a/packages/SystemUI/res/drawable/stat_sys_media.xml b/packages/SystemUI/res/drawable/stat_sys_media.xml
new file mode 100644
index 0000000000000..d48db7bd0d28a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_media.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 8bbcfa0e78982..de483179a92a0 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -790,6 +790,9 @@
Sensors off active
+
+ Media is active
+
Clear all notifications.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index a065b74bda997..2a4475bbe6b52 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -46,6 +46,8 @@ import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.qualifiers.DisplayId;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
+import com.android.systemui.media.MediaData;
+import com.android.systemui.media.MediaDataManager;
import com.android.systemui.qs.tiles.DndTile;
import com.android.systemui.qs.tiles.RotationLockTile;
import com.android.systemui.screenrecord.RecordingController;
@@ -80,14 +82,14 @@ import javax.inject.Inject;
*/
public class PhoneStatusBarPolicy
implements BluetoothController.Callback,
- CommandQueue.Callbacks,
- RotationLockControllerCallback,
- Listener,
- ZenModeController.Callback,
- DeviceProvisionedListener,
- KeyguardStateController.Callback,
- LocationController.LocationChangeCallback,
- RecordingController.RecordingStateChangeCallback {
+ CommandQueue.Callbacks,
+ RotationLockControllerCallback,
+ Listener,
+ ZenModeController.Callback,
+ DeviceProvisionedListener,
+ KeyguardStateController.Callback,
+ LocationController.LocationChangeCallback,
+ RecordingController.RecordingStateChangeCallback, MediaDataManager.Listener {
private static final String TAG = "PhoneStatusBarPolicy";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -108,6 +110,7 @@ public class PhoneStatusBarPolicy
private final String mSlotLocation;
private final String mSlotSensorsOff;
private final String mSlotScreenRecord;
+ private final String mSlotMedia;
private final int mDisplayId;
private final SharedPreferences mSharedPreferences;
private final DateFormatUtil mDateFormatUtil;
@@ -135,6 +138,7 @@ public class PhoneStatusBarPolicy
private final SensorPrivacyController mSensorPrivacyController;
private final RecordingController mRecordingController;
private final RingerModeTracker mRingerModeTracker;
+ private final MediaDataManager mMediaDataManager;
private boolean mZenVisible;
private boolean mVolumeVisible;
@@ -159,6 +163,7 @@ public class PhoneStatusBarPolicy
SensorPrivacyController sensorPrivacyController, IActivityManager iActivityManager,
AlarmManager alarmManager, UserManager userManager,
RecordingController recordingController,
+ MediaDataManager mediaDataManager,
@Nullable TelecomManager telecomManager, @DisplayId int displayId,
@Main SharedPreferences sharedPreferences, DateFormatUtil dateFormatUtil,
RingerModeTracker ringerModeTracker) {
@@ -185,6 +190,7 @@ public class PhoneStatusBarPolicy
mUiBgExecutor = uiBgExecutor;
mTelecomManager = telecomManager;
mRingerModeTracker = ringerModeTracker;
+ mMediaDataManager = mediaDataManager;
mSlotCast = resources.getString(com.android.internal.R.string.status_bar_cast);
mSlotHotspot = resources.getString(com.android.internal.R.string.status_bar_hotspot);
@@ -202,6 +208,7 @@ public class PhoneStatusBarPolicy
mSlotSensorsOff = resources.getString(com.android.internal.R.string.status_bar_sensors_off);
mSlotScreenRecord = resources.getString(
com.android.internal.R.string.status_bar_screen_record);
+ mSlotMedia = resources.getString(com.android.internal.R.string.status_bar_media);
mDisplayId = displayId;
mSharedPreferences = sharedPreferences;
@@ -280,6 +287,11 @@ public class PhoneStatusBarPolicy
mIconController.setIconVisibility(mSlotSensorsOff,
mSensorPrivacyController.isSensorPrivacyEnabled());
+ // play/pause icon when media is active
+ mIconController.setIcon(mSlotMedia, R.drawable.stat_sys_media,
+ mResources.getString(R.string.accessibility_media_active));
+ mIconController.setIconVisibility(mSlotMedia, mMediaDataManager.hasActiveMedia());
+
// screen record
mIconController.setIcon(mSlotScreenRecord, R.drawable.stat_sys_screen_record, null);
mIconController.setIconVisibility(mSlotScreenRecord, false);
@@ -296,6 +308,7 @@ public class PhoneStatusBarPolicy
mSensorPrivacyController.addCallback(mSensorPrivacyListener);
mLocationController.addCallback(this);
mRecordingController.addCallback(this);
+ mMediaDataManager.addListener(this);
mCommandQueue.addCallback(this);
}
@@ -700,4 +713,18 @@ public class PhoneStatusBarPolicy
if (DEBUG) Log.d(TAG, "screenrecord: hiding icon");
mHandler.post(() -> mIconController.setIconVisibility(mSlotScreenRecord, false));
}
+
+ @Override
+ public void onMediaDataLoaded(String key, MediaData data) {
+ updateMediaIcon();
+ }
+
+ @Override
+ public void onMediaDataRemoved(String key) {
+ updateMediaIcon();
+ }
+
+ private void updateMediaIcon() {
+ mIconController.setIconVisibility(mSlotMedia, mMediaDataManager.hasActiveMedia());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.java
new file mode 100644
index 0000000000000..a14d57556360c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.AlarmManager;
+import android.app.IActivityManager;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.os.UserManager;
+import android.telecom.TelecomManager;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.media.MediaDataManager;
+import com.android.systemui.screenrecord.RecordingController;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.policy.BluetoothController;
+import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.DataSaverController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.HotspotController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.NextAlarmController;
+import com.android.systemui.statusbar.policy.RotationLockController;
+import com.android.systemui.statusbar.policy.SensorPrivacyController;
+import com.android.systemui.statusbar.policy.UserInfoController;
+import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.util.RingerModeLiveData;
+import com.android.systemui.util.RingerModeTracker;
+import com.android.systemui.util.time.DateFormatUtil;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.concurrent.Executor;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class PhoneStatusBarPolicyTest extends SysuiTestCase {
+
+ private static final int DISPLAY_ID = 0;
+ @Mock
+ private StatusBarIconController mIconController;
+ @Mock
+ private CommandQueue mCommandQueue;
+ @Mock
+ private BroadcastDispatcher mBroadcastDispatcher;
+ @Mock
+ private Executor mBackgroundExecutor;
+ @Mock
+ private CastController mCastController;
+ @Mock
+ private HotspotController mHotSpotController;
+ @Mock
+ private BluetoothController mBluetoothController;
+ @Mock
+ private NextAlarmController mNextAlarmController;
+ @Mock
+ private UserInfoController mUserInfoController;
+ @Mock
+ private RotationLockController mRotationLockController;
+ @Mock
+ private DataSaverController mDataSaverController;
+ @Mock
+ private ZenModeController mZenModeController;
+ @Mock
+ private DeviceProvisionedController mDeviceProvisionerController;
+ @Mock
+ private KeyguardStateController mKeyguardStateController;
+ @Mock
+ private LocationController mLocationController;
+ @Mock
+ private SensorPrivacyController mSensorPrivacyController;
+ @Mock
+ private IActivityManager mIActivityManager;
+ @Mock
+ private AlarmManager mAlarmManager;
+ @Mock
+ private UserManager mUserManager;
+ @Mock
+ private RecordingController mRecordingController;
+ @Mock
+ private MediaDataManager mMediaDataManager;
+ @Mock
+ private TelecomManager mTelecomManager;
+ @Mock
+ private SharedPreferences mSharedPreferences;
+ @Mock
+ private DateFormatUtil mDateFormatUtil;
+ @Mock
+ private RingerModeTracker mRingerModeTracker;
+ @Mock
+ private RingerModeLiveData mRingerModeLiveData;
+ @Rule
+ public MockitoRule rule = MockitoJUnit.rule();
+ private Resources mResources;
+ private PhoneStatusBarPolicy mPhoneStatusBarPolicy;
+
+ @Before
+ public void setup() {
+ mResources = spy(getContext().getResources());
+ mPhoneStatusBarPolicy = new PhoneStatusBarPolicy(mIconController, mCommandQueue,
+ mBroadcastDispatcher, mBackgroundExecutor, mResources, mCastController,
+ mHotSpotController, mBluetoothController, mNextAlarmController, mUserInfoController,
+ mRotationLockController, mDataSaverController, mZenModeController,
+ mDeviceProvisionerController, mKeyguardStateController, mLocationController,
+ mSensorPrivacyController, mIActivityManager, mAlarmManager, mUserManager,
+ mRecordingController, mMediaDataManager, mTelecomManager, DISPLAY_ID,
+ mSharedPreferences, mDateFormatUtil, mRingerModeTracker);
+ when(mRingerModeTracker.getRingerMode()).thenReturn(mRingerModeLiveData);
+ when(mRingerModeTracker.getRingerModeInternal()).thenReturn(mRingerModeLiveData);
+ clearInvocations(mIconController);
+ }
+
+ @Test
+ public void testInit_registerMediaCallback() {
+ mPhoneStatusBarPolicy.init();
+ verify(mMediaDataManager).addListener(eq(mPhoneStatusBarPolicy));
+ }
+
+ @Test
+ public void testOnMediaDataLoaded_updatesIcon_hasMedia() {
+ String mediaSlot = mResources.getString(com.android.internal.R.string.status_bar_media);
+ when(mMediaDataManager.hasActiveMedia()).thenReturn(true);
+ mPhoneStatusBarPolicy.onMediaDataLoaded(null, null);
+ verify(mMediaDataManager).hasActiveMedia();
+ verify(mIconController).setIconVisibility(eq(mediaSlot), eq(true));
+ }
+
+ @Test
+ public void testOnMediaDataRemoved_updatesIcon_noMedia() {
+ String mediaSlot = mResources.getString(com.android.internal.R.string.status_bar_media);
+ mPhoneStatusBarPolicy.onMediaDataRemoved(null);
+ verify(mMediaDataManager).hasActiveMedia();
+ verify(mIconController).setIconVisibility(eq(mediaSlot), eq(false));
+ }
+}