diff options
| author | 2018-01-23 13:55:18 -0500 | |
|---|---|---|
| committer | 2018-01-24 15:22:25 +0000 | |
| commit | f5e4182d2fdf7cee3a95ed4734b7b2533bdeddc9 (patch) | |
| tree | 84e173b94e869467e6fb30e59b0a525fc29d2e4b | |
| parent | 25ff1cd41f27adee9d2f399883cef924c4e9a1fa (diff) | |
Output chooser layout updates
- Anchor output chooser to volume buttons
- Dismiss output chooser if volume dialog becomes visible
Test: manual, runtest systemui
Fixes: 72319160
Bug: 63096355
Change-Id: Ibca7576f287655fb5c98554e67781ec53152ddef
5 files changed, 193 insertions, 54 deletions
diff --git a/packages/SystemUI/res/layout/output_chooser.xml b/packages/SystemUI/res/layout/output_chooser.xml index b96f44750a0c..b9f7b152ecac 100644 --- a/packages/SystemUI/res/layout/output_chooser.xml +++ b/packages/SystemUI/res/layout/output_chooser.xml @@ -15,47 +15,56 @@ limitations under the License. --> <!-- extends LinearLayout --> -<com.android.systemui.volume.OutputChooserLayout +<com.android.systemui.HardwareUiLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:sysui="http://schemas.android.com/apk/res-auto" - android:id="@+id/output_chooser" - android:minWidth="320dp" - android:minHeight="320dp" android:layout_width="match_parent" android:layout_height="match_parent" - android:orientation="vertical" - android:padding="20dp" > - - <TextView - android:id="@+id/title" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textDirection="locale" - android:textAppearance="@style/TextAppearance.QS.DetailHeader" - android:layout_marginBottom="20dp" /> - - <com.android.systemui.qs.AutoSizingList - android:id="@android:id/list" - android:layout_width="match_parent" - android:layout_height="match_parent" + android:layout_marginBottom="0dp" + android:clipToPadding="false" + android:theme="@style/qs_theme" + android:clipChildren="false"> + <com.android.systemui.volume.OutputChooserLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:sysui="http://schemas.android.com/apk/res-auto" + android:id="@+id/output_chooser" + android:layout_width="@dimen/output_chooser_panel_width" + android:layout_height="@dimen/output_chooser_panel_width" + android:layout_gravity="center_vertical|end" android:orientation="vertical" - sysui:itemHeight="@dimen/qs_detail_item_height" - style="@style/AutoSizingList"/> - - <LinearLayout - android:id="@android:id/empty" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_gravity="center" - android:gravity="center" - android:orientation="vertical"> + android:translationZ="8dp" + android:padding="20dp" > <TextView - android:id="@+id/empty_text" + android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textDirection="locale" - android:layout_marginTop="20dp" - android:textAppearance="@style/TextAppearance.QS.DetailEmpty"/> - </LinearLayout> -</com.android.systemui.volume.OutputChooserLayout> + android:textAppearance="@style/TextAppearance.QS.DetailHeader" + android:layout_marginBottom="20dp" /> + + <com.android.systemui.qs.AutoSizingList + android:id="@android:id/list" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + sysui:itemHeight="@dimen/qs_detail_item_height" + style="@style/AutoSizingList"/> + + <LinearLayout + android:id="@android:id/empty" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_gravity="center" + android:gravity="center" + android:orientation="vertical"> + + <TextView + android:id="@+id/empty_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textDirection="locale" + android:layout_marginTop="20dp" + android:textAppearance="@style/TextAppearance.QS.DetailEmpty"/> + </LinearLayout> + </com.android.systemui.volume.OutputChooserLayout> +</com.android.systemui.HardwareUiLayout> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index b749a18a8c68..a90106d7131a 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -267,6 +267,8 @@ <dimen name="volume_dialog_panel_width">120dp</dimen> + <dimen name="output_chooser_panel_width">320dp</dimen> + <!-- Gravity for the notification panel --> <integer name="notification_panel_layout_gravity">0x31</integer><!-- center_horizontal|top --> diff --git a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java index ca34345d923b..948178802003 100644 --- a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java +++ b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java @@ -58,6 +58,7 @@ public class HardwareUiLayout extends FrameLayout implements Tunable { private boolean mRoundedDivider; private int mRotation = ROTATION_NONE; private boolean mRotatedBackground; + private boolean mSwapOrientation = true; public HardwareUiLayout(Context context, AttributeSet attrs) { super(context, attrs); @@ -145,6 +146,10 @@ public class HardwareUiLayout extends FrameLayout implements Tunable { updateRotation(); } + public void setSwapOrientation(boolean swapOrientation) { + mSwapOrientation = swapOrientation; + } + private void updateRotation() { int rotation = RotationUtils.getRotation(getContext()); if (rotation != mRotation) { @@ -173,7 +178,9 @@ public class HardwareUiLayout extends FrameLayout implements Tunable { if (to == ROTATION_SEASCAPE) { swapOrder(linearLayout); } - linearLayout.setOrientation(LinearLayout.HORIZONTAL); + if (mSwapOrientation) { + linearLayout.setOrientation(LinearLayout.HORIZONTAL); + } swapDimens(this.mChild); } } else { @@ -184,7 +191,9 @@ public class HardwareUiLayout extends FrameLayout implements Tunable { if (from == ROTATION_SEASCAPE) { swapOrder(linearLayout); } - linearLayout.setOrientation(LinearLayout.VERTICAL); + if (mSwapOrientation) { + linearLayout.setOrientation(LinearLayout.VERTICAL); + } swapDimens(mChild); } } diff --git a/packages/SystemUI/src/com/android/systemui/volume/OutputChooserDialog.java b/packages/SystemUI/src/com/android/systemui/volume/OutputChooserDialog.java index e0af9baf0bb0..e3c8503077d8 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/OutputChooserDialog.java +++ b/packages/SystemUI/src/com/android/systemui/volume/OutputChooserDialog.java @@ -22,6 +22,7 @@ import static android.support.v7.media.MediaRouter.UNSELECT_REASON_DISCONNECTED; import static com.android.settingslib.bluetooth.Utils.getBtClassDrawableWithDescription; +import android.app.Dialog; import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; @@ -30,6 +31,8 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.net.wifi.WifiManager; @@ -43,12 +46,16 @@ import android.support.v7.media.MediaRouter; import android.telecom.TelecomManager; import android.util.Log; import android.util.Pair; +import android.view.Window; +import android.view.WindowManager; import com.android.settingslib.Utils; import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.systemui.Dependency; +import com.android.systemui.HardwareUiLayout; +import com.android.systemui.Interpolators; import com.android.systemui.R; -import com.android.systemui.statusbar.phone.SystemUIDialog; +import com.android.systemui.plugins.VolumeDialogController; import com.android.systemui.statusbar.policy.BluetoothController; import java.io.IOException; @@ -58,7 +65,7 @@ import java.util.Collection; import java.util.Comparator; import java.util.List; -public class OutputChooserDialog extends SystemUIDialog +public class OutputChooserDialog extends Dialog implements DialogInterface.OnDismissListener, OutputChooserLayout.Callback { private static final String TAG = Util.logTag(OutputChooserDialog.class); @@ -82,9 +89,11 @@ public class OutputChooserDialog extends SystemUIDialog private Drawable mTvIcon; private Drawable mSpeakerIcon; private Drawable mSpeakerGroupIcon; + private HardwareUiLayout mHardwareLayout; + private final VolumeDialogController mController; public OutputChooserDialog(Context context, MediaRouterWrapper router) { - super(context); + super(context, com.android.systemui.R.style.qs_theme); mContext = context; mBluetoothController = Dependency.get(BluetoothController.class); mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); @@ -98,6 +107,22 @@ public class OutputChooserDialog extends SystemUIDialog final IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); context.registerReceiver(mReceiver, filter); + + mController = Dependency.get(VolumeDialogController.class); + + // Window initialization + Window window = getWindow(); + window.requestFeature(Window.FEATURE_NO_TITLE); + window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); + window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND + | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR); + window.addFlags( + WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN + | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED + | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH + | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED); + window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY); } protected void setIsInCall(boolean inCall) { @@ -112,6 +137,9 @@ public class OutputChooserDialog extends SystemUIDialog setOnDismissListener(this::onDismiss); mView = findViewById(R.id.output_chooser); + mHardwareLayout = HardwareUiLayout.get(mView); + mHardwareLayout.setOutsideTouchListener(view -> dismiss()); + mHardwareLayout.setSwapOrientation(false); mView.setCallback(this); if (mIsInCall) { @@ -151,6 +179,7 @@ public class OutputChooserDialog extends SystemUIDialog MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN); } mBluetoothController.addCallback(mCallback); + mController.addCallback(mControllerCallbackH, mHandler); isAttached = true; } @@ -158,6 +187,7 @@ public class OutputChooserDialog extends SystemUIDialog public void onDetachedFromWindow() { isAttached = false; mRouter.removeCallback(mRouterCallback); + mController.removeCallback(mControllerCallbackH); mBluetoothController.removeCallback(mCallback); super.onDetachedFromWindow(); } @@ -169,6 +199,38 @@ public class OutputChooserDialog extends SystemUIDialog } @Override + public void show() { + super.show(); + mHardwareLayout.setTranslationX(getAnimTranslation()); + mHardwareLayout.setAlpha(0); + mHardwareLayout.animate() + .alpha(1) + .translationX(0) + .setDuration(300) + .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) + .withEndAction(() -> getWindow().getDecorView().requestAccessibilityFocus()) + .start(); + } + + @Override + public void dismiss() { + mHardwareLayout.setTranslationX(0); + mHardwareLayout.setAlpha(1); + mHardwareLayout.animate() + .alpha(0) + .translationX(getAnimTranslation()) + .setDuration(300) + .withEndAction(() -> super.dismiss()) + .setInterpolator(new SystemUIInterpolators.LogAccelerateInterpolator()) + .start(); + } + + private float getAnimTranslation() { + return getContext().getResources().getDimension( + com.android.systemui.R.dimen.output_chooser_panel_width) / 2; + } + + @Override public void onDetailItemClick(OutputChooserLayout.Item item) { if (item == null || item.tag == null) return; if (item.deviceType == OutputChooserLayout.Item.DEVICE_TYPE_BT) { @@ -416,4 +478,41 @@ public class OutputChooserDialog extends SystemUIDialog } } }; + + private final VolumeDialogController.Callbacks mControllerCallbackH + = new VolumeDialogController.Callbacks() { + @Override + public void onShowRequested(int reason) { + dismiss(); + } + + @Override + public void onDismissRequested(int reason) {} + + @Override + public void onScreenOff() { + dismiss(); + } + + @Override + public void onStateChanged(VolumeDialogController.State state) {} + + @Override + public void onLayoutDirectionChanged(int layoutDirection) {} + + @Override + public void onConfigurationChanged() {} + + @Override + public void onShowVibrateHint() {} + + @Override + public void onShowSilentHint() {} + + @Override + public void onShowSafetyWarning(int flags) {} + + @Override + public void onAccessibilityModeChanged(Boolean showA11yStream) {} + }; }
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/OutputChooserDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/OutputChooserDialogTest.java index 537d606365c4..de99d71351c7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/volume/OutputChooserDialogTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/volume/OutputChooserDialogTest.java @@ -38,6 +38,7 @@ import android.widget.TextView; import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.plugins.VolumeDialogController; import com.android.systemui.statusbar.policy.BluetoothController; import org.junit.After; @@ -54,6 +55,8 @@ public class OutputChooserDialogTest extends SysuiTestCase { OutputChooserDialog mDialog; @Mock + private VolumeDialogController mVolumeController; + @Mock private BluetoothController mController; @Mock private WifiManager mWifiManager; @@ -69,6 +72,7 @@ public class OutputChooserDialogTest extends SysuiTestCase { public void setup() throws Exception { MockitoAnnotations.initMocks(this); + mVolumeController = mDependency.injectMockDependency(VolumeDialogController.class); mController = mDependency.injectMockDependency(BluetoothController.class); when(mWifiManager.isWifiEnabled()).thenReturn(true); @@ -78,20 +82,10 @@ public class OutputChooserDialogTest extends SysuiTestCase { mDialog = new OutputChooserDialog(getContext(), mRouter); } - @After - @UiThreadTest - public void tearDown() throws Exception { - mDialog.dismiss(); - } - - private void showDialog() { - mDialog.show(); - } - @Test @UiThreadTest public void testClickMediaRouterItemConnectsMedia() { - showDialog(); + mDialog.show(); OutputChooserLayout.Item item = new OutputChooserLayout.Item(); item.deviceType = OutputChooserLayout.Item.DEVICE_TYPE_MEDIA_ROUTER; @@ -102,12 +96,13 @@ public class OutputChooserDialogTest extends SysuiTestCase { mDialog.onDetailItemClick(item); verify(info, times(1)).select(); verify(mController, never()).connect(any()); + mDialog.dismiss(); } @Test @UiThreadTest public void testClickBtItemConnectsBt() { - showDialog(); + mDialog.show(); OutputChooserLayout.Item item = new OutputChooserLayout.Item(); item.deviceType = OutputChooserLayout.Item.DEVICE_TYPE_BT; @@ -117,25 +112,28 @@ public class OutputChooserDialogTest extends SysuiTestCase { mDialog.onDetailItemClick(item); verify(mController, times(1)).connect(any()); + mDialog.dismiss(); } @Test @UiThreadTest public void testTitleNotInCall() { - showDialog(); + mDialog.show(); assertTrue(((TextView) mDialog.findViewById(R.id.title)) .getText().toString().contains("Media")); + mDialog.dismiss(); } @Test @UiThreadTest public void testTitleInCall() { mDialog.setIsInCall(true); - showDialog(); + mDialog.show(); assertTrue(((TextView) mDialog.findViewById(R.id.title)) .getText().toString().contains("Phone")); + mDialog.dismiss(); } @Test @@ -155,4 +153,26 @@ public class OutputChooserDialogTest extends SysuiTestCase { verify(mRouter, times(1)).addCallback(any(), any(), anyInt()); } + + @Test + @UiThreadTest + public void testRegisterCallbacks() { + mDialog.setIsInCall(false); + mDialog.onAttachedToWindow(); + + verify(mRouter, times(1)).addCallback(any(), any(), anyInt()); + verify(mController, times(1)).addCallback(any()); + verify(mVolumeController, times(1)).addCallback(any(), any()); + } + + @Test + @UiThreadTest + public void testUnregisterCallbacks() { + mDialog.setIsInCall(false); + mDialog.onDetachedFromWindow(); + + verify(mRouter, times(1)).removeCallback(any()); + verify(mController, times(1)).removeCallback(any()); + verify(mVolumeController, times(1)).removeCallback(any()); + } } |