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
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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 -->
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -168,6 +198,38 @@ public class OutputChooserDialog extends SystemUIDialog
|
||||
cleanUp();
|
||||
}
|
||||
|
||||
@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;
|
||||
@@ -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) {}
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
@@ -53,6 +54,8 @@ public class OutputChooserDialogTest extends SysuiTestCase {
|
||||
|
||||
OutputChooserDialog mDialog;
|
||||
|
||||
@Mock
|
||||
private VolumeDialogController mVolumeController;
|
||||
@Mock
|
||||
private BluetoothController mController;
|
||||
@Mock
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user