Loading packages/SystemUI/src/com/android/systemui/volume/Events.java +4 −1 Original line number Diff line number Diff line Loading @@ -98,6 +98,8 @@ public class Events { public static final int DISMISS_REASON_OUTPUT_CHOOSER = 8; public static final int DISMISS_REASON_USB_OVERHEAD_ALARM_CHANGED = 9; public static final int DISMISS_REASON_CSD_WARNING_TIMEOUT = 10; public static final int DISMISS_REASON_POSTURE_CHANGED = 11; public static final String[] DISMISS_REASONS = { "unknown", "touch_outside", Loading @@ -109,7 +111,8 @@ public class Events { "a11y_stream_changed", "output_chooser", "usb_temperature_below_threshold", "csd_warning_timeout" "csd_warning_timeout", "posture_changed" }; public static final int SHOW_REASON_UNKNOWN = 0; Loading packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java +65 −11 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static com.android.internal.jank.InteractionJankMonitor.CUJ_VOLUME_CONTROL; import static com.android.internal.jank.InteractionJankMonitor.Configuration.Builder; import static com.android.systemui.volume.Events.DISMISS_REASON_POSTURE_CHANGED; import static com.android.systemui.volume.Events.DISMISS_REASON_SETTINGS_CLICKED; import android.animation.Animator; Loading Loading @@ -129,6 +130,7 @@ import com.android.systemui.plugins.VolumeDialogController.State; import com.android.systemui.plugins.VolumeDialogController.StreamState; import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.DevicePostureController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.util.AlphaTintDrawableWrapper; import com.android.systemui.util.DeviceConfigProxy; Loading Loading @@ -184,7 +186,7 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, private final boolean mChangeVolumeRowTintWhenInactive; private final Context mContext; private final H mHandler = new H(); private final H mHandler; private final VolumeDialogController mController; private final DeviceProvisionedController mDeviceProvisionedController; private final Region mTouchableRegion = new Region(); Loading Loading @@ -259,16 +261,13 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, private final AccessibilityManagerWrapper mAccessibilityMgr; private final Object mSafetyWarningLock = new Object(); private final Accessibility mAccessibility = new Accessibility(); private final ConfigurationController mConfigurationController; private final MediaOutputDialogFactory mMediaOutputDialogFactory; private final VolumePanelFactory mVolumePanelFactory; private final CsdWarningDialog.Factory mCsdWarningDialogFactory; private final ActivityStarter mActivityStarter; private boolean mShowing; private boolean mShowA11yStream; private int mActiveStream; private int mPrevActiveStream; private boolean mAutomute = VolumePrefs.DEFAULT_ENABLE_AUTOMUTE; Loading Loading @@ -300,6 +299,12 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, @VisibleForTesting int mVolumeRingerMuteIconDrawableId; private int mOriginalGravity; private final DevicePostureController.Callback mDevicePostureControllerCallback; private final DevicePostureController mDevicePostureController; private @DevicePostureController.DevicePostureInt int mDevicePosture; private int mOrientation; public VolumeDialogImpl( Context context, VolumeDialogController volumeDialogController, Loading @@ -313,9 +318,12 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, DeviceConfigProxy deviceConfigProxy, Executor executor, CsdWarningDialog.Factory csdWarningDialogFactory, DevicePostureController devicePostureController, Looper looper, DumpManager dumpManager) { mContext = new ContextThemeWrapper(context, R.style.volume_dialog_theme); mHandler = new H(looper); mController = volumeDialogController; mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); Loading Loading @@ -357,6 +365,16 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, initDimens(); mOrientation = mContext.getResources().getConfiguration().orientation; mDevicePostureController = devicePostureController; if (mDevicePostureController != null) { int initialPosture = mDevicePostureController.getDevicePosture(); mDevicePosture = initialPosture; mDevicePostureControllerCallback = this::onPostureChanged; } else { mDevicePostureControllerCallback = null; } mDeviceConfigProxy = deviceConfigProxy; mExecutor = executor; mSeparateNotification = mDeviceConfigProxy.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI, Loading @@ -364,6 +382,25 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, updateRingerModeIconSet(); } /** * Adjust the dialog location on the screen in order to avoid drawing on the hinge. */ private void adjustPositionOnScreen() { final boolean isPortrait = mOrientation == Configuration.ORIENTATION_PORTRAIT; final boolean isHalfOpen = mDevicePosture == DevicePostureController.DEVICE_POSTURE_HALF_OPENED; final boolean isTabletop = isPortrait && isHalfOpen; WindowManager.LayoutParams lp = mWindow.getAttributes(); int gravity = isTabletop ? (mOriginalGravity | Gravity.TOP) : mOriginalGravity; mWindowGravity = Gravity.getAbsoluteGravity(gravity, mContext.getResources().getConfiguration().getLayoutDirection()); lp.gravity = mWindowGravity; } @VisibleForTesting int getWindowGravity() { return mWindowGravity; } /** * If ringer and notification are the same stream (T and earlier), use notification-like bell * icon set. Loading Loading @@ -419,6 +456,10 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, mDeviceConfigProxy.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI, mExecutor, this::onDeviceConfigChange); if (mDevicePostureController != null) { mDevicePostureController.addCallback(mDevicePostureControllerCallback); } } @Override Loading @@ -427,6 +468,9 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, mHandler.removeCallbacksAndMessages(null); mConfigurationController.removeCallback(this); mDeviceConfigProxy.removeOnPropertiesChangedListener(this::onDeviceConfigChange); if (mDevicePostureController != null) { mDevicePostureController.removeCallback(mDevicePostureControllerCallback); } } /** Loading @@ -441,7 +485,6 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, mSeparateNotification = newVal; updateRingerModeIconSet(); updateRingRowIcon(); } } } Loading Loading @@ -500,7 +543,6 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, private void initDialog(int lockTaskModeState) { mDialog = new CustomDialog(mContext); initDimens(); mConfigurableTexts = new ConfigurableTexts(mContext); Loading @@ -524,14 +566,13 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, lp.setTitle(VolumeDialogImpl.class.getSimpleName()); lp.windowAnimations = -1; mWindowGravity = Gravity.getAbsoluteGravity( mContext.getResources().getInteger(R.integer.volume_dialog_gravity), mOriginalGravity = mContext.getResources().getInteger(R.integer.volume_dialog_gravity); mWindowGravity = Gravity.getAbsoluteGravity(mOriginalGravity, mContext.getResources().getConfiguration().getLayoutDirection()); lp.gravity = mWindowGravity; mWindow.setAttributes(lp); mWindow.setLayout(WRAP_CONTENT, WRAP_CONTENT); mDialog.setContentView(R.layout.volume_dialog); mDialogView = mDialog.findViewById(R.id.volume_dialog); mDialogView.setAlpha(0); Loading Loading @@ -1539,8 +1580,10 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, animator.translationX( (isWindowGravityLeft() ? -1 : 1) * mDialogView.getWidth() / 2.0f); } animator.setListener(getJankListener(getDialogView(), TYPE_DISMISS, mDialogHideAnimationDurationMs)).start(); checkODICaptionsTooltip(true); synchronized (mSafetyWarningLock) { if (mSafetyWarning != null) { Loading Loading @@ -2237,6 +2280,11 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, mTopContainer.setBackground(background); } @Override public void onConfigChanged(Configuration config) { mOrientation = config.orientation; } private final VolumeDialogController.Callbacks mControllerCallbackH = new VolumeDialogController.Callbacks() { @Override Loading Loading @@ -2313,6 +2361,11 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, } }; @VisibleForTesting void onPostureChanged(int posture) { dismiss(DISMISS_REASON_POSTURE_CHANGED); mDevicePosture = posture; } private final class H extends Handler { private static final int SHOW = 1; private static final int DISMISS = 2; Loading @@ -2323,8 +2376,8 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, private static final int STATE_CHANGED = 7; private static final int CSD_TIMEOUT = 8; public H() { super(Looper.getMainLooper()); H(Looper looper) { super(looper); } @Override Loading Loading @@ -2370,6 +2423,7 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, protected void onStart() { super.setCanceledOnTouchOutside(true); super.onStart(); adjustPositionOnScreen(); } @Override Loading packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java +5 −1 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.systemui.volume.dagger; import android.content.Context; import android.media.AudioManager; import android.os.Looper; import com.android.internal.jank.InteractionJankMonitor; import com.android.systemui.dagger.qualifiers.Main; Loading @@ -28,6 +29,7 @@ import com.android.systemui.plugins.VolumeDialog; import com.android.systemui.plugins.VolumeDialogController; import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.DevicePostureController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.util.DeviceConfigProxy; import com.android.systemui.volume.CsdWarningDialog; Loading @@ -42,7 +44,6 @@ import dagger.Provides; import java.util.concurrent.Executor; /** Dagger Module for code in the volume package. */ @Module public interface VolumeModule { Loading @@ -65,6 +66,7 @@ public interface VolumeModule { DeviceConfigProxy deviceConfigProxy, @Main Executor executor, CsdWarningDialog.Factory csdFactory, DevicePostureController devicePostureController, DumpManager dumpManager) { VolumeDialogImpl impl = new VolumeDialogImpl( context, Loading @@ -79,6 +81,8 @@ public interface VolumeModule { deviceConfigProxy, executor, csdFactory, devicePostureController, Looper.getMainLooper(), dumpManager); impl.setStreamImportant(AudioManager.STREAM_SYSTEM, false); impl.setAutomute(true); Loading packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java +185 −4 Original line number Diff line number Diff line Loading @@ -17,22 +17,28 @@ package com.android.systemui.volume; import static com.android.systemui.volume.Events.DISMISS_REASON_UNKNOWN; import static com.android.systemui.volume.Events.SHOW_REASON_UNKNOWN; import static com.android.systemui.volume.VolumeDialogControllerImpl.STREAMS; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.KeyguardManager; import android.content.res.Configuration; import android.media.AudioManager; import android.os.SystemClock; import android.provider.DeviceConfig; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.view.Gravity; import android.view.InputDevice; import android.view.MotionEvent; import android.view.View; Loading @@ -53,7 +59,9 @@ import com.android.systemui.plugins.VolumeDialogController; import com.android.systemui.plugins.VolumeDialogController.State; import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.DevicePostureController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.FakeConfigurationController; import com.android.systemui.util.DeviceConfigProxyFake; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.time.FakeSystemClock; Loading Loading @@ -82,6 +90,9 @@ public class VolumeDialogImplTest extends SysuiTestCase { View mDrawerNormal; private DeviceConfigProxyFake mDeviceConfigProxy; private FakeExecutor mExecutor; private TestableLooper mTestableLooper; private ConfigurationController mConfigurationController; private int mOriginalOrientation; @Mock VolumeDialogController mVolumeDialogController; Loading @@ -92,8 +103,6 @@ public class VolumeDialogImplTest extends SysuiTestCase { @Mock DeviceProvisionedController mDeviceProvisionedController; @Mock ConfigurationController mConfigurationController; @Mock MediaOutputDialogFactory mMediaOutputDialogFactory; @Mock VolumePanelFactory mVolumePanelFactory; Loading @@ -104,6 +113,8 @@ public class VolumeDialogImplTest extends SysuiTestCase { @Mock private DumpManager mDumpManager; @Mock CsdWarningDialog mCsdWarningDialog; @Mock DevicePostureController mPostureController; private final CsdWarningDialog.Factory mCsdWarningDialogFactory = new CsdWarningDialog.Factory() { Loading @@ -119,9 +130,17 @@ public class VolumeDialogImplTest extends SysuiTestCase { getContext().addMockSystemService(KeyguardManager.class, mKeyguard); mTestableLooper = TestableLooper.get(this); mDeviceConfigProxy = new DeviceConfigProxyFake(); mExecutor = new FakeExecutor(new FakeSystemClock()); when(mPostureController.getDevicePosture()) .thenReturn(DevicePostureController.DEVICE_POSTURE_CLOSED); mOriginalOrientation = mContext.getResources().getConfiguration().orientation; mConfigurationController = new FakeConfigurationController(); mDialog = new VolumeDialogImpl( getContext(), mVolumeDialogController, Loading @@ -135,8 +154,9 @@ public class VolumeDialogImplTest extends SysuiTestCase { mDeviceConfigProxy, mExecutor, mCsdWarningDialogFactory, mDumpManager ); mPostureController, mTestableLooper.getLooper(), mDumpManager); mDialog.init(0, null); State state = createShellState(); mDialog.onStateChangedH(state); Loading Loading @@ -227,6 +247,7 @@ public class VolumeDialogImplTest extends SysuiTestCase { ArgumentCaptor.forClass(VolumeDialogController.Callbacks.class); verify(mVolumeDialogController).addCallback(controllerCallbackCapture.capture(), any()); VolumeDialogController.Callbacks callbacks = controllerCallbackCapture.getValue(); callbacks.onShowSafetyWarning(AudioManager.FLAG_SHOW_UI); verify(mAccessibilityMgr).getRecommendedTimeoutMillis( VolumeDialogImpl.DIALOG_SAFETYWARNING_TIMEOUT_MILLIS, Loading Loading @@ -371,11 +392,171 @@ public class VolumeDialogImplTest extends SysuiTestCase { verify(mCsdWarningDialog).show(); } @Test public void ifPortraitHalfOpen_drawVerticallyTop() { DevicePostureController devicePostureController = mock(DevicePostureController.class); when(devicePostureController.getDevicePosture()) .thenReturn(DevicePostureController.DEVICE_POSTURE_CLOSED); VolumeDialogImpl dialog = new VolumeDialogImpl( getContext(), mVolumeDialogController, mAccessibilityMgr, mDeviceProvisionedController, mConfigurationController, mMediaOutputDialogFactory, mVolumePanelFactory, mActivityStarter, mInteractionJankMonitor, mDeviceConfigProxy, mExecutor, mCsdWarningDialogFactory, devicePostureController, mTestableLooper.getLooper(), mDumpManager ); dialog.init(0 , null); verify(devicePostureController).addCallback(any()); dialog.onPostureChanged(DevicePostureController.DEVICE_POSTURE_HALF_OPENED); mTestableLooper.processAllMessages(); // let dismiss() finish setOrientation(Configuration.ORIENTATION_PORTRAIT); // Call show() to trigger layout updates before verifying position dialog.show(SHOW_REASON_UNKNOWN); mTestableLooper.processAllMessages(); // let show() finish before assessing its side-effect int gravity = dialog.getWindowGravity(); assertEquals(Gravity.TOP, gravity & Gravity.VERTICAL_GRAVITY_MASK); } @Test public void ifPortraitAndOpen_drawCenterVertically() { DevicePostureController devicePostureController = mock(DevicePostureController.class); when(devicePostureController.getDevicePosture()) .thenReturn(DevicePostureController.DEVICE_POSTURE_CLOSED); VolumeDialogImpl dialog = new VolumeDialogImpl( getContext(), mVolumeDialogController, mAccessibilityMgr, mDeviceProvisionedController, mConfigurationController, mMediaOutputDialogFactory, mVolumePanelFactory, mActivityStarter, mInteractionJankMonitor, mDeviceConfigProxy, mExecutor, mCsdWarningDialogFactory, devicePostureController, mTestableLooper.getLooper(), mDumpManager ); dialog.init(0, null); verify(devicePostureController).addCallback(any()); dialog.onPostureChanged(DevicePostureController.DEVICE_POSTURE_OPENED); mTestableLooper.processAllMessages(); // let dismiss() finish setOrientation(Configuration.ORIENTATION_PORTRAIT); dialog.show(SHOW_REASON_UNKNOWN); mTestableLooper.processAllMessages(); // let show() finish before assessing its side-effect int gravity = dialog.getWindowGravity(); assertEquals(Gravity.CENTER_VERTICAL, gravity & Gravity.VERTICAL_GRAVITY_MASK); } @Test public void ifLandscapeAndHalfOpen_drawCenterVertically() { DevicePostureController devicePostureController = mock(DevicePostureController.class); when(devicePostureController.getDevicePosture()) .thenReturn(DevicePostureController.DEVICE_POSTURE_CLOSED); VolumeDialogImpl dialog = new VolumeDialogImpl( getContext(), mVolumeDialogController, mAccessibilityMgr, mDeviceProvisionedController, mConfigurationController, mMediaOutputDialogFactory, mVolumePanelFactory, mActivityStarter, mInteractionJankMonitor, mDeviceConfigProxy, mExecutor, mCsdWarningDialogFactory, devicePostureController, mTestableLooper.getLooper(), mDumpManager ); dialog.init(0, null); verify(devicePostureController).addCallback(any()); dialog.onPostureChanged(DevicePostureController.DEVICE_POSTURE_HALF_OPENED); mTestableLooper.processAllMessages(); // let dismiss() finish setOrientation(Configuration.ORIENTATION_LANDSCAPE); dialog.show(SHOW_REASON_UNKNOWN); mTestableLooper.processAllMessages(); // let show() finish before assessing its side-effect int gravity = dialog.getWindowGravity(); assertEquals(Gravity.CENTER_VERTICAL, gravity & Gravity.VERTICAL_GRAVITY_MASK); } @Test public void dialogInit_addsPostureControllerCallback() { // init is already called in setup verify(mPostureController).addCallback(any()); } @Test public void dialogDestroy_removesPostureControllerCallback() { VolumeDialogImpl dialog = new VolumeDialogImpl( getContext(), mVolumeDialogController, mAccessibilityMgr, mDeviceProvisionedController, mConfigurationController, mMediaOutputDialogFactory, mVolumePanelFactory, mActivityStarter, mInteractionJankMonitor, mDeviceConfigProxy, mExecutor, mCsdWarningDialogFactory, mPostureController, mTestableLooper.getLooper(), mDumpManager ); dialog.init(0, null); verify(mPostureController, never()).removeCallback(any()); dialog.destroy(); verify(mPostureController).removeCallback(any()); } private void setOrientation(int orientation) { Configuration config = new Configuration(); config.orientation = orientation; if (mConfigurationController != null) { mConfigurationController.onConfigurationChanged(config); } } @After public void teardown() { if (mDialog != null) { mDialog.clearInternalHandlerAfterTest(); } setOrientation(mOriginalOrientation); mTestableLooper.processAllMessages(); reset(mPostureController); } /* Loading Loading
packages/SystemUI/src/com/android/systemui/volume/Events.java +4 −1 Original line number Diff line number Diff line Loading @@ -98,6 +98,8 @@ public class Events { public static final int DISMISS_REASON_OUTPUT_CHOOSER = 8; public static final int DISMISS_REASON_USB_OVERHEAD_ALARM_CHANGED = 9; public static final int DISMISS_REASON_CSD_WARNING_TIMEOUT = 10; public static final int DISMISS_REASON_POSTURE_CHANGED = 11; public static final String[] DISMISS_REASONS = { "unknown", "touch_outside", Loading @@ -109,7 +111,8 @@ public class Events { "a11y_stream_changed", "output_chooser", "usb_temperature_below_threshold", "csd_warning_timeout" "csd_warning_timeout", "posture_changed" }; public static final int SHOW_REASON_UNKNOWN = 0; Loading
packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java +65 −11 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static com.android.internal.jank.InteractionJankMonitor.CUJ_VOLUME_CONTROL; import static com.android.internal.jank.InteractionJankMonitor.Configuration.Builder; import static com.android.systemui.volume.Events.DISMISS_REASON_POSTURE_CHANGED; import static com.android.systemui.volume.Events.DISMISS_REASON_SETTINGS_CLICKED; import android.animation.Animator; Loading Loading @@ -129,6 +130,7 @@ import com.android.systemui.plugins.VolumeDialogController.State; import com.android.systemui.plugins.VolumeDialogController.StreamState; import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.DevicePostureController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.util.AlphaTintDrawableWrapper; import com.android.systemui.util.DeviceConfigProxy; Loading Loading @@ -184,7 +186,7 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, private final boolean mChangeVolumeRowTintWhenInactive; private final Context mContext; private final H mHandler = new H(); private final H mHandler; private final VolumeDialogController mController; private final DeviceProvisionedController mDeviceProvisionedController; private final Region mTouchableRegion = new Region(); Loading Loading @@ -259,16 +261,13 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, private final AccessibilityManagerWrapper mAccessibilityMgr; private final Object mSafetyWarningLock = new Object(); private final Accessibility mAccessibility = new Accessibility(); private final ConfigurationController mConfigurationController; private final MediaOutputDialogFactory mMediaOutputDialogFactory; private final VolumePanelFactory mVolumePanelFactory; private final CsdWarningDialog.Factory mCsdWarningDialogFactory; private final ActivityStarter mActivityStarter; private boolean mShowing; private boolean mShowA11yStream; private int mActiveStream; private int mPrevActiveStream; private boolean mAutomute = VolumePrefs.DEFAULT_ENABLE_AUTOMUTE; Loading Loading @@ -300,6 +299,12 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, @VisibleForTesting int mVolumeRingerMuteIconDrawableId; private int mOriginalGravity; private final DevicePostureController.Callback mDevicePostureControllerCallback; private final DevicePostureController mDevicePostureController; private @DevicePostureController.DevicePostureInt int mDevicePosture; private int mOrientation; public VolumeDialogImpl( Context context, VolumeDialogController volumeDialogController, Loading @@ -313,9 +318,12 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, DeviceConfigProxy deviceConfigProxy, Executor executor, CsdWarningDialog.Factory csdWarningDialogFactory, DevicePostureController devicePostureController, Looper looper, DumpManager dumpManager) { mContext = new ContextThemeWrapper(context, R.style.volume_dialog_theme); mHandler = new H(looper); mController = volumeDialogController; mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); Loading Loading @@ -357,6 +365,16 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, initDimens(); mOrientation = mContext.getResources().getConfiguration().orientation; mDevicePostureController = devicePostureController; if (mDevicePostureController != null) { int initialPosture = mDevicePostureController.getDevicePosture(); mDevicePosture = initialPosture; mDevicePostureControllerCallback = this::onPostureChanged; } else { mDevicePostureControllerCallback = null; } mDeviceConfigProxy = deviceConfigProxy; mExecutor = executor; mSeparateNotification = mDeviceConfigProxy.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI, Loading @@ -364,6 +382,25 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, updateRingerModeIconSet(); } /** * Adjust the dialog location on the screen in order to avoid drawing on the hinge. */ private void adjustPositionOnScreen() { final boolean isPortrait = mOrientation == Configuration.ORIENTATION_PORTRAIT; final boolean isHalfOpen = mDevicePosture == DevicePostureController.DEVICE_POSTURE_HALF_OPENED; final boolean isTabletop = isPortrait && isHalfOpen; WindowManager.LayoutParams lp = mWindow.getAttributes(); int gravity = isTabletop ? (mOriginalGravity | Gravity.TOP) : mOriginalGravity; mWindowGravity = Gravity.getAbsoluteGravity(gravity, mContext.getResources().getConfiguration().getLayoutDirection()); lp.gravity = mWindowGravity; } @VisibleForTesting int getWindowGravity() { return mWindowGravity; } /** * If ringer and notification are the same stream (T and earlier), use notification-like bell * icon set. Loading Loading @@ -419,6 +456,10 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, mDeviceConfigProxy.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI, mExecutor, this::onDeviceConfigChange); if (mDevicePostureController != null) { mDevicePostureController.addCallback(mDevicePostureControllerCallback); } } @Override Loading @@ -427,6 +468,9 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, mHandler.removeCallbacksAndMessages(null); mConfigurationController.removeCallback(this); mDeviceConfigProxy.removeOnPropertiesChangedListener(this::onDeviceConfigChange); if (mDevicePostureController != null) { mDevicePostureController.removeCallback(mDevicePostureControllerCallback); } } /** Loading @@ -441,7 +485,6 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, mSeparateNotification = newVal; updateRingerModeIconSet(); updateRingRowIcon(); } } } Loading Loading @@ -500,7 +543,6 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, private void initDialog(int lockTaskModeState) { mDialog = new CustomDialog(mContext); initDimens(); mConfigurableTexts = new ConfigurableTexts(mContext); Loading @@ -524,14 +566,13 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, lp.setTitle(VolumeDialogImpl.class.getSimpleName()); lp.windowAnimations = -1; mWindowGravity = Gravity.getAbsoluteGravity( mContext.getResources().getInteger(R.integer.volume_dialog_gravity), mOriginalGravity = mContext.getResources().getInteger(R.integer.volume_dialog_gravity); mWindowGravity = Gravity.getAbsoluteGravity(mOriginalGravity, mContext.getResources().getConfiguration().getLayoutDirection()); lp.gravity = mWindowGravity; mWindow.setAttributes(lp); mWindow.setLayout(WRAP_CONTENT, WRAP_CONTENT); mDialog.setContentView(R.layout.volume_dialog); mDialogView = mDialog.findViewById(R.id.volume_dialog); mDialogView.setAlpha(0); Loading Loading @@ -1539,8 +1580,10 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, animator.translationX( (isWindowGravityLeft() ? -1 : 1) * mDialogView.getWidth() / 2.0f); } animator.setListener(getJankListener(getDialogView(), TYPE_DISMISS, mDialogHideAnimationDurationMs)).start(); checkODICaptionsTooltip(true); synchronized (mSafetyWarningLock) { if (mSafetyWarning != null) { Loading Loading @@ -2237,6 +2280,11 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, mTopContainer.setBackground(background); } @Override public void onConfigChanged(Configuration config) { mOrientation = config.orientation; } private final VolumeDialogController.Callbacks mControllerCallbackH = new VolumeDialogController.Callbacks() { @Override Loading Loading @@ -2313,6 +2361,11 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, } }; @VisibleForTesting void onPostureChanged(int posture) { dismiss(DISMISS_REASON_POSTURE_CHANGED); mDevicePosture = posture; } private final class H extends Handler { private static final int SHOW = 1; private static final int DISMISS = 2; Loading @@ -2323,8 +2376,8 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, private static final int STATE_CHANGED = 7; private static final int CSD_TIMEOUT = 8; public H() { super(Looper.getMainLooper()); H(Looper looper) { super(looper); } @Override Loading Loading @@ -2370,6 +2423,7 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, protected void onStart() { super.setCanceledOnTouchOutside(true); super.onStart(); adjustPositionOnScreen(); } @Override Loading
packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java +5 −1 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.systemui.volume.dagger; import android.content.Context; import android.media.AudioManager; import android.os.Looper; import com.android.internal.jank.InteractionJankMonitor; import com.android.systemui.dagger.qualifiers.Main; Loading @@ -28,6 +29,7 @@ import com.android.systemui.plugins.VolumeDialog; import com.android.systemui.plugins.VolumeDialogController; import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.DevicePostureController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.util.DeviceConfigProxy; import com.android.systemui.volume.CsdWarningDialog; Loading @@ -42,7 +44,6 @@ import dagger.Provides; import java.util.concurrent.Executor; /** Dagger Module for code in the volume package. */ @Module public interface VolumeModule { Loading @@ -65,6 +66,7 @@ public interface VolumeModule { DeviceConfigProxy deviceConfigProxy, @Main Executor executor, CsdWarningDialog.Factory csdFactory, DevicePostureController devicePostureController, DumpManager dumpManager) { VolumeDialogImpl impl = new VolumeDialogImpl( context, Loading @@ -79,6 +81,8 @@ public interface VolumeModule { deviceConfigProxy, executor, csdFactory, devicePostureController, Looper.getMainLooper(), dumpManager); impl.setStreamImportant(AudioManager.STREAM_SYSTEM, false); impl.setAutomute(true); Loading
packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java +185 −4 Original line number Diff line number Diff line Loading @@ -17,22 +17,28 @@ package com.android.systemui.volume; import static com.android.systemui.volume.Events.DISMISS_REASON_UNKNOWN; import static com.android.systemui.volume.Events.SHOW_REASON_UNKNOWN; import static com.android.systemui.volume.VolumeDialogControllerImpl.STREAMS; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.KeyguardManager; import android.content.res.Configuration; import android.media.AudioManager; import android.os.SystemClock; import android.provider.DeviceConfig; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.view.Gravity; import android.view.InputDevice; import android.view.MotionEvent; import android.view.View; Loading @@ -53,7 +59,9 @@ import com.android.systemui.plugins.VolumeDialogController; import com.android.systemui.plugins.VolumeDialogController.State; import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.DevicePostureController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.FakeConfigurationController; import com.android.systemui.util.DeviceConfigProxyFake; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.time.FakeSystemClock; Loading Loading @@ -82,6 +90,9 @@ public class VolumeDialogImplTest extends SysuiTestCase { View mDrawerNormal; private DeviceConfigProxyFake mDeviceConfigProxy; private FakeExecutor mExecutor; private TestableLooper mTestableLooper; private ConfigurationController mConfigurationController; private int mOriginalOrientation; @Mock VolumeDialogController mVolumeDialogController; Loading @@ -92,8 +103,6 @@ public class VolumeDialogImplTest extends SysuiTestCase { @Mock DeviceProvisionedController mDeviceProvisionedController; @Mock ConfigurationController mConfigurationController; @Mock MediaOutputDialogFactory mMediaOutputDialogFactory; @Mock VolumePanelFactory mVolumePanelFactory; Loading @@ -104,6 +113,8 @@ public class VolumeDialogImplTest extends SysuiTestCase { @Mock private DumpManager mDumpManager; @Mock CsdWarningDialog mCsdWarningDialog; @Mock DevicePostureController mPostureController; private final CsdWarningDialog.Factory mCsdWarningDialogFactory = new CsdWarningDialog.Factory() { Loading @@ -119,9 +130,17 @@ public class VolumeDialogImplTest extends SysuiTestCase { getContext().addMockSystemService(KeyguardManager.class, mKeyguard); mTestableLooper = TestableLooper.get(this); mDeviceConfigProxy = new DeviceConfigProxyFake(); mExecutor = new FakeExecutor(new FakeSystemClock()); when(mPostureController.getDevicePosture()) .thenReturn(DevicePostureController.DEVICE_POSTURE_CLOSED); mOriginalOrientation = mContext.getResources().getConfiguration().orientation; mConfigurationController = new FakeConfigurationController(); mDialog = new VolumeDialogImpl( getContext(), mVolumeDialogController, Loading @@ -135,8 +154,9 @@ public class VolumeDialogImplTest extends SysuiTestCase { mDeviceConfigProxy, mExecutor, mCsdWarningDialogFactory, mDumpManager ); mPostureController, mTestableLooper.getLooper(), mDumpManager); mDialog.init(0, null); State state = createShellState(); mDialog.onStateChangedH(state); Loading Loading @@ -227,6 +247,7 @@ public class VolumeDialogImplTest extends SysuiTestCase { ArgumentCaptor.forClass(VolumeDialogController.Callbacks.class); verify(mVolumeDialogController).addCallback(controllerCallbackCapture.capture(), any()); VolumeDialogController.Callbacks callbacks = controllerCallbackCapture.getValue(); callbacks.onShowSafetyWarning(AudioManager.FLAG_SHOW_UI); verify(mAccessibilityMgr).getRecommendedTimeoutMillis( VolumeDialogImpl.DIALOG_SAFETYWARNING_TIMEOUT_MILLIS, Loading Loading @@ -371,11 +392,171 @@ public class VolumeDialogImplTest extends SysuiTestCase { verify(mCsdWarningDialog).show(); } @Test public void ifPortraitHalfOpen_drawVerticallyTop() { DevicePostureController devicePostureController = mock(DevicePostureController.class); when(devicePostureController.getDevicePosture()) .thenReturn(DevicePostureController.DEVICE_POSTURE_CLOSED); VolumeDialogImpl dialog = new VolumeDialogImpl( getContext(), mVolumeDialogController, mAccessibilityMgr, mDeviceProvisionedController, mConfigurationController, mMediaOutputDialogFactory, mVolumePanelFactory, mActivityStarter, mInteractionJankMonitor, mDeviceConfigProxy, mExecutor, mCsdWarningDialogFactory, devicePostureController, mTestableLooper.getLooper(), mDumpManager ); dialog.init(0 , null); verify(devicePostureController).addCallback(any()); dialog.onPostureChanged(DevicePostureController.DEVICE_POSTURE_HALF_OPENED); mTestableLooper.processAllMessages(); // let dismiss() finish setOrientation(Configuration.ORIENTATION_PORTRAIT); // Call show() to trigger layout updates before verifying position dialog.show(SHOW_REASON_UNKNOWN); mTestableLooper.processAllMessages(); // let show() finish before assessing its side-effect int gravity = dialog.getWindowGravity(); assertEquals(Gravity.TOP, gravity & Gravity.VERTICAL_GRAVITY_MASK); } @Test public void ifPortraitAndOpen_drawCenterVertically() { DevicePostureController devicePostureController = mock(DevicePostureController.class); when(devicePostureController.getDevicePosture()) .thenReturn(DevicePostureController.DEVICE_POSTURE_CLOSED); VolumeDialogImpl dialog = new VolumeDialogImpl( getContext(), mVolumeDialogController, mAccessibilityMgr, mDeviceProvisionedController, mConfigurationController, mMediaOutputDialogFactory, mVolumePanelFactory, mActivityStarter, mInteractionJankMonitor, mDeviceConfigProxy, mExecutor, mCsdWarningDialogFactory, devicePostureController, mTestableLooper.getLooper(), mDumpManager ); dialog.init(0, null); verify(devicePostureController).addCallback(any()); dialog.onPostureChanged(DevicePostureController.DEVICE_POSTURE_OPENED); mTestableLooper.processAllMessages(); // let dismiss() finish setOrientation(Configuration.ORIENTATION_PORTRAIT); dialog.show(SHOW_REASON_UNKNOWN); mTestableLooper.processAllMessages(); // let show() finish before assessing its side-effect int gravity = dialog.getWindowGravity(); assertEquals(Gravity.CENTER_VERTICAL, gravity & Gravity.VERTICAL_GRAVITY_MASK); } @Test public void ifLandscapeAndHalfOpen_drawCenterVertically() { DevicePostureController devicePostureController = mock(DevicePostureController.class); when(devicePostureController.getDevicePosture()) .thenReturn(DevicePostureController.DEVICE_POSTURE_CLOSED); VolumeDialogImpl dialog = new VolumeDialogImpl( getContext(), mVolumeDialogController, mAccessibilityMgr, mDeviceProvisionedController, mConfigurationController, mMediaOutputDialogFactory, mVolumePanelFactory, mActivityStarter, mInteractionJankMonitor, mDeviceConfigProxy, mExecutor, mCsdWarningDialogFactory, devicePostureController, mTestableLooper.getLooper(), mDumpManager ); dialog.init(0, null); verify(devicePostureController).addCallback(any()); dialog.onPostureChanged(DevicePostureController.DEVICE_POSTURE_HALF_OPENED); mTestableLooper.processAllMessages(); // let dismiss() finish setOrientation(Configuration.ORIENTATION_LANDSCAPE); dialog.show(SHOW_REASON_UNKNOWN); mTestableLooper.processAllMessages(); // let show() finish before assessing its side-effect int gravity = dialog.getWindowGravity(); assertEquals(Gravity.CENTER_VERTICAL, gravity & Gravity.VERTICAL_GRAVITY_MASK); } @Test public void dialogInit_addsPostureControllerCallback() { // init is already called in setup verify(mPostureController).addCallback(any()); } @Test public void dialogDestroy_removesPostureControllerCallback() { VolumeDialogImpl dialog = new VolumeDialogImpl( getContext(), mVolumeDialogController, mAccessibilityMgr, mDeviceProvisionedController, mConfigurationController, mMediaOutputDialogFactory, mVolumePanelFactory, mActivityStarter, mInteractionJankMonitor, mDeviceConfigProxy, mExecutor, mCsdWarningDialogFactory, mPostureController, mTestableLooper.getLooper(), mDumpManager ); dialog.init(0, null); verify(mPostureController, never()).removeCallback(any()); dialog.destroy(); verify(mPostureController).removeCallback(any()); } private void setOrientation(int orientation) { Configuration config = new Configuration(); config.orientation = orientation; if (mConfigurationController != null) { mConfigurationController.onConfigurationChanged(config); } } @After public void teardown() { if (mDialog != null) { mDialog.clearInternalHandlerAfterTest(); } setOrientation(mOriginalOrientation); mTestableLooper.processAllMessages(); reset(mPostureController); } /* Loading