Add MediaOutputAdapter for Media device list
-Build device item layout by different cases -Provide UI component for different operations -Add MediaOutputBaseAdapter for common method -Add MediaOutputAdapterTest for unit test Bug: 155822415 Test: atest MediaOutputAdapterTest Merged-In: Ida509ed401320b3665d7a5f29f4df5db096ff29c Change-Id: Ida509ed401320b3665d7a5f29f4df5db096ff29c
This commit is contained in:
112
packages/SystemUI/res/layout/media_output_list_item.xml
Normal file
112
packages/SystemUI/res/layout/media_output_list_item.xml
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/device_container"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="64dp">
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="36dp"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_marginStart="16dp">
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/title_icon"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"/>
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_marginStart="68dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
android:textSize="14sp"/>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/two_line_layout"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:layout_marginStart="52dp"
|
||||||
|
android:layout_marginEnd="69dp"
|
||||||
|
android:layout_marginTop="10dp">
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/two_line_title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginEnd="15dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
android:textSize="14sp"/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/subtitle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginEnd="15dp"
|
||||||
|
android:layout_marginBottom="7dp"
|
||||||
|
android:layout_alignParentBottom="true"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:fontFamily="roboto-regular"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/volume_indeterminate_progress"
|
||||||
|
style="@*android:style/Widget.Material.ProgressBar.Horizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginEnd="15dp"
|
||||||
|
android:layout_marginBottom="1dp"
|
||||||
|
android:layout_alignParentBottom="true"
|
||||||
|
android:indeterminate="true"
|
||||||
|
android:indeterminateOnly="true"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
<SeekBar
|
||||||
|
android:id="@+id/volume_seekbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentBottom="true"/>
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="1dp"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:layout_marginEnd="68dp"
|
||||||
|
android:layout_gravity="right|center_vertical"
|
||||||
|
android:background="?android:attr/listDivider"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/end_icon"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_gravity="right|center_vertical"
|
||||||
|
android:layout_marginEnd="24dp"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
</FrameLayout>
|
||||||
@@ -0,0 +1,163 @@
|
|||||||
|
/*
|
||||||
|
* 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.media.dialog;
|
||||||
|
|
||||||
|
import static android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE;
|
||||||
|
|
||||||
|
import android.graphics.PorterDuff;
|
||||||
|
import android.graphics.PorterDuffColorFilter;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.text.SpannableString;
|
||||||
|
import android.text.style.ForegroundColorSpan;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import com.android.settingslib.Utils;
|
||||||
|
import com.android.settingslib.media.LocalMediaManager.MediaDeviceState;
|
||||||
|
import com.android.settingslib.media.MediaDevice;
|
||||||
|
import com.android.systemui.R;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapter for media output dialog.
|
||||||
|
*/
|
||||||
|
public class MediaOutputAdapter extends MediaOutputBaseAdapter {
|
||||||
|
|
||||||
|
private static final String TAG = "MediaOutputAdapter";
|
||||||
|
private static final int PAIR_NEW = 1;
|
||||||
|
|
||||||
|
public MediaOutputAdapter(MediaOutputController controller) {
|
||||||
|
super(controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MediaDeviceBaseViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup,
|
||||||
|
int viewType) {
|
||||||
|
super.onCreateViewHolder(viewGroup, viewType);
|
||||||
|
|
||||||
|
return new MediaDeviceViewHolder(mHolderView);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(@NonNull MediaDeviceBaseViewHolder viewHolder, int position) {
|
||||||
|
if (mController.isZeroMode() && position == (mController.getMediaDevices().size())) {
|
||||||
|
viewHolder.onBind(PAIR_NEW);
|
||||||
|
} else if (position < (mController.getMediaDevices().size())) {
|
||||||
|
viewHolder.onBind(((List<MediaDevice>) (mController.getMediaDevices())).get(position));
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "Incorrect position: " + position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
if (mController.isZeroMode()) {
|
||||||
|
// Add extra one for "pair new"
|
||||||
|
return mController.getMediaDevices().size() + 1;
|
||||||
|
}
|
||||||
|
return mController.getMediaDevices().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void onItemClick(MediaDevice device) {
|
||||||
|
mController.connectDevice(device);
|
||||||
|
device.setState(MediaDeviceState.STATE_CONNECTING);
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void onItemClick(int customizedItem) {
|
||||||
|
if (customizedItem == PAIR_NEW) {
|
||||||
|
mController.launchBluetoothPairing();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
CharSequence getItemTitle(MediaDevice device) {
|
||||||
|
if (device.getDeviceType() == MediaDevice.MediaDeviceType.TYPE_BLUETOOTH_DEVICE
|
||||||
|
&& !device.isConnected()) {
|
||||||
|
final CharSequence deviceName = device.getName();
|
||||||
|
// Append status to title only for the disconnected Bluetooth device.
|
||||||
|
final SpannableString spannableTitle = new SpannableString(
|
||||||
|
mContext.getString(R.string.media_output_dialog_disconnected, deviceName));
|
||||||
|
spannableTitle.setSpan(new ForegroundColorSpan(
|
||||||
|
Utils.getColorAttrDefaultColor(mContext, android.R.attr.textColorSecondary)),
|
||||||
|
deviceName.length(),
|
||||||
|
spannableTitle.length(), SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
return spannableTitle;
|
||||||
|
}
|
||||||
|
return super.getItemTitle(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
class MediaDeviceViewHolder extends MediaDeviceBaseViewHolder {
|
||||||
|
|
||||||
|
MediaDeviceViewHolder(View view) {
|
||||||
|
super(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void onBind(MediaDevice device) {
|
||||||
|
super.onBind(device);
|
||||||
|
if (mController.isTransferring()) {
|
||||||
|
if (device.getState() == MediaDeviceState.STATE_CONNECTING
|
||||||
|
&& !mController.hasAdjustVolumeUserRestriction()) {
|
||||||
|
setTwoLineLayout(device, true);
|
||||||
|
mProgressBar.setVisibility(View.VISIBLE);
|
||||||
|
mSeekBar.setVisibility(View.GONE);
|
||||||
|
mSubTitleText.setVisibility(View.GONE);
|
||||||
|
} else {
|
||||||
|
setSingleLineLayout(getItemTitle(device), false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Set different layout for each device
|
||||||
|
if (device.getState() == MediaDeviceState.STATE_CONNECTING_FAILED) {
|
||||||
|
setTwoLineLayout(device, false);
|
||||||
|
mSubTitleText.setVisibility(View.VISIBLE);
|
||||||
|
mSeekBar.setVisibility(View.GONE);
|
||||||
|
mProgressBar.setVisibility(View.GONE);
|
||||||
|
mSubTitleText.setText(R.string.media_output_dialog_connect_failed);
|
||||||
|
mFrameLayout.setOnClickListener(v -> onItemClick(device));
|
||||||
|
} else if (!mController.hasAdjustVolumeUserRestriction()
|
||||||
|
&& isCurrentConnected(device)) {
|
||||||
|
setTwoLineLayout(device, true);
|
||||||
|
mSeekBar.setVisibility(View.VISIBLE);
|
||||||
|
mProgressBar.setVisibility(View.GONE);
|
||||||
|
mSubTitleText.setVisibility(View.GONE);
|
||||||
|
initSeekbar(device);
|
||||||
|
} else {
|
||||||
|
setSingleLineLayout(getItemTitle(device), false);
|
||||||
|
mFrameLayout.setOnClickListener(v -> onItemClick(device));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void onBind(int customizedItem) {
|
||||||
|
if (customizedItem == PAIR_NEW) {
|
||||||
|
setSingleLineLayout(mContext.getText(R.string.media_output_dialog_pairing_new),
|
||||||
|
false);
|
||||||
|
final Drawable d = mContext.getDrawable(R.drawable.ic_add);
|
||||||
|
d.setColorFilter(new PorterDuffColorFilter(
|
||||||
|
Utils.getColorAccentDefaultColor(mContext), PorterDuff.Mode.SRC_IN));
|
||||||
|
mTitleIcon.setImageDrawable(d);
|
||||||
|
mFrameLayout.setOnClickListener(v -> onItemClick(PAIR_NEW));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,165 @@
|
|||||||
|
/*
|
||||||
|
* 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.media.dialog;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Typeface;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.ProgressBar;
|
||||||
|
import android.widget.RelativeLayout;
|
||||||
|
import android.widget.SeekBar;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import com.android.settingslib.media.MediaDevice;
|
||||||
|
import com.android.systemui.R;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base adapter for media output dialog.
|
||||||
|
*/
|
||||||
|
public abstract class MediaOutputBaseAdapter extends
|
||||||
|
RecyclerView.Adapter<MediaOutputBaseAdapter.MediaDeviceBaseViewHolder> {
|
||||||
|
|
||||||
|
private static final String FONT_SELECTED_TITLE = "sans-serif-medium";
|
||||||
|
private static final String FONT_TITLE = "sans-serif";
|
||||||
|
|
||||||
|
final MediaOutputController mController;
|
||||||
|
|
||||||
|
private boolean mIsDragging;
|
||||||
|
|
||||||
|
Context mContext;
|
||||||
|
View mHolderView;
|
||||||
|
|
||||||
|
public MediaOutputBaseAdapter(MediaOutputController controller) {
|
||||||
|
mController = controller;
|
||||||
|
mIsDragging = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MediaDeviceBaseViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup,
|
||||||
|
int viewType) {
|
||||||
|
mContext = viewGroup.getContext();
|
||||||
|
mHolderView = LayoutInflater.from(mContext).inflate(R.layout.media_output_list_item,
|
||||||
|
viewGroup, false);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
CharSequence getItemTitle(MediaDevice device) {
|
||||||
|
return device.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isCurrentConnected(MediaDevice device) {
|
||||||
|
return TextUtils.equals(device.getId(),
|
||||||
|
mController.getCurrentConnectedMediaDevice().getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isDragging() {
|
||||||
|
return mIsDragging;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ViewHolder for binding device view.
|
||||||
|
*/
|
||||||
|
abstract class MediaDeviceBaseViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
final FrameLayout mFrameLayout;
|
||||||
|
final TextView mTitleText;
|
||||||
|
final TextView mTwoLineTitleText;
|
||||||
|
final TextView mSubTitleText;
|
||||||
|
final ImageView mTitleIcon;
|
||||||
|
final ImageView mEndIcon;
|
||||||
|
final ProgressBar mProgressBar;
|
||||||
|
final SeekBar mSeekBar;
|
||||||
|
final RelativeLayout mTwoLineLayout;
|
||||||
|
|
||||||
|
MediaDeviceBaseViewHolder(View view) {
|
||||||
|
super(view);
|
||||||
|
mFrameLayout = view.requireViewById(R.id.device_container);
|
||||||
|
mTitleText = view.requireViewById(R.id.title);
|
||||||
|
mSubTitleText = view.requireViewById(R.id.subtitle);
|
||||||
|
mTwoLineLayout = view.requireViewById(R.id.two_line_layout);
|
||||||
|
mTwoLineTitleText = view.requireViewById(R.id.two_line_title);
|
||||||
|
mTitleIcon = view.requireViewById(R.id.title_icon);
|
||||||
|
mEndIcon = view.requireViewById(R.id.end_icon);
|
||||||
|
mProgressBar = view.requireViewById(R.id.volume_indeterminate_progress);
|
||||||
|
mSeekBar = view.requireViewById(R.id.volume_seekbar);
|
||||||
|
}
|
||||||
|
|
||||||
|
void onBind(MediaDevice device) {
|
||||||
|
mTitleIcon.setImageIcon(mController.getDeviceIconCompat(device).toIcon(mContext));
|
||||||
|
}
|
||||||
|
|
||||||
|
void onBind(int customizedItem) { }
|
||||||
|
|
||||||
|
void setSingleLineLayout(CharSequence title, boolean bFocused) {
|
||||||
|
mTitleText.setVisibility(View.VISIBLE);
|
||||||
|
mTwoLineLayout.setVisibility(View.GONE);
|
||||||
|
mTitleText.setText(title);
|
||||||
|
if (bFocused) {
|
||||||
|
mTitleText.setTypeface(Typeface.create(FONT_SELECTED_TITLE, Typeface.NORMAL));
|
||||||
|
} else {
|
||||||
|
mTitleText.setTypeface(Typeface.create(FONT_TITLE, Typeface.NORMAL));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTwoLineLayout(MediaDevice device, boolean bFocused) {
|
||||||
|
mTitleText.setVisibility(View.GONE);
|
||||||
|
mTwoLineLayout.setVisibility(View.VISIBLE);
|
||||||
|
mTwoLineTitleText.setText(getItemTitle(device));
|
||||||
|
if (bFocused) {
|
||||||
|
mTwoLineTitleText.setTypeface(Typeface.create(FONT_SELECTED_TITLE,
|
||||||
|
Typeface.NORMAL));
|
||||||
|
} else {
|
||||||
|
mTwoLineTitleText.setTypeface(Typeface.create(FONT_TITLE, Typeface.NORMAL));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void initSeekbar(MediaDevice device) {
|
||||||
|
mSeekBar.setMax(device.getMaxVolume());
|
||||||
|
mSeekBar.setMin(0);
|
||||||
|
if (mSeekBar.getProgress() != device.getCurrentVolume()) {
|
||||||
|
mSeekBar.setProgress(device.getCurrentVolume());
|
||||||
|
}
|
||||||
|
mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||||
|
if (device == null || !fromUser) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mController.adjustVolume(device, progress);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||||
|
mIsDragging = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||||
|
mIsDragging = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,200 @@
|
|||||||
|
/*
|
||||||
|
* 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.media.dialog;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.graphics.drawable.Icon;
|
||||||
|
import android.testing.AndroidTestingRunner;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
|
||||||
|
import androidx.core.graphics.drawable.IconCompat;
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
|
import com.android.settingslib.media.LocalMediaManager;
|
||||||
|
import com.android.settingslib.media.MediaDevice;
|
||||||
|
import com.android.systemui.R;
|
||||||
|
import com.android.systemui.SysuiTestCase;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidTestingRunner.class)
|
||||||
|
public class MediaOutputAdapterTest extends SysuiTestCase {
|
||||||
|
|
||||||
|
private static final String TEST_DEVICE_NAME_1 = "test_device_name_1";
|
||||||
|
private static final String TEST_DEVICE_NAME_2 = "test_device_name_2";
|
||||||
|
private static final String TEST_DEVICE_ID_1 = "test_device_id_1";
|
||||||
|
private static final String TEST_DEVICE_ID_2 = "test_device_id_2";
|
||||||
|
|
||||||
|
// Mock
|
||||||
|
private MediaOutputController mMediaOutputController = mock(MediaOutputController.class);
|
||||||
|
private MediaDevice mMediaDevice1 = mock(MediaDevice.class);
|
||||||
|
private MediaDevice mMediaDevice2 = mock(MediaDevice.class);
|
||||||
|
private Icon mIcon = mock(Icon.class);
|
||||||
|
private IconCompat mIconCompat = mock(IconCompat.class);
|
||||||
|
|
||||||
|
private MediaOutputAdapter mMediaOutputAdapter;
|
||||||
|
private MediaOutputAdapter.MediaDeviceViewHolder mViewHolder;
|
||||||
|
private List<MediaDevice> mMediaDevices = new ArrayList<>();
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
mMediaOutputAdapter = new MediaOutputAdapter(mMediaOutputController);
|
||||||
|
mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
|
||||||
|
.onCreateViewHolder(new FrameLayout(mContext), 0);
|
||||||
|
|
||||||
|
when(mMediaOutputController.getMediaDevices()).thenReturn(mMediaDevices);
|
||||||
|
when(mMediaOutputController.hasAdjustVolumeUserRestriction()).thenReturn(false);
|
||||||
|
when(mMediaOutputController.isZeroMode()).thenReturn(false);
|
||||||
|
when(mMediaOutputController.isTransferring()).thenReturn(false);
|
||||||
|
when(mMediaOutputController.getDeviceIconCompat(mMediaDevice1)).thenReturn(mIconCompat);
|
||||||
|
when(mMediaOutputController.getDeviceIconCompat(mMediaDevice2)).thenReturn(mIconCompat);
|
||||||
|
when(mMediaOutputController.getCurrentConnectedMediaDevice()).thenReturn(mMediaDevice1);
|
||||||
|
when(mIconCompat.toIcon(mContext)).thenReturn(mIcon);
|
||||||
|
when(mMediaDevice1.getName()).thenReturn(TEST_DEVICE_NAME_1);
|
||||||
|
when(mMediaDevice1.getId()).thenReturn(TEST_DEVICE_ID_1);
|
||||||
|
when(mMediaDevice2.getName()).thenReturn(TEST_DEVICE_NAME_2);
|
||||||
|
when(mMediaDevice2.getId()).thenReturn(TEST_DEVICE_ID_2);
|
||||||
|
when(mMediaDevice1.getState()).thenReturn(
|
||||||
|
LocalMediaManager.MediaDeviceState.STATE_CONNECTED);
|
||||||
|
when(mMediaDevice2.getState()).thenReturn(
|
||||||
|
LocalMediaManager.MediaDeviceState.STATE_DISCONNECTED);
|
||||||
|
mMediaDevices.add(mMediaDevice1);
|
||||||
|
mMediaDevices.add(mMediaDevice2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getItemCount_nonZeroMode_isDeviceSize() {
|
||||||
|
assertThat(mMediaOutputAdapter.getItemCount()).isEqualTo(mMediaDevices.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getItemCount_zeroMode_containExtraOneForPairNew() {
|
||||||
|
when(mMediaOutputController.isZeroMode()).thenReturn(true);
|
||||||
|
|
||||||
|
assertThat(mMediaOutputAdapter.getItemCount()).isEqualTo(mMediaDevices.size() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onBindViewHolder_zeroMode_bindPairNew_verifyView() {
|
||||||
|
when(mMediaOutputController.isZeroMode()).thenReturn(true);
|
||||||
|
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 2);
|
||||||
|
|
||||||
|
assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE);
|
||||||
|
assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.GONE);
|
||||||
|
assertThat(mViewHolder.mTitleText.getText()).isEqualTo(mContext.getText(
|
||||||
|
R.string.media_output_dialog_pairing_new));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onBindViewHolder_bindConnectedDevice_verifyView() {
|
||||||
|
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
|
||||||
|
|
||||||
|
assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
|
||||||
|
assertThat(mViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE);
|
||||||
|
assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
|
||||||
|
assertThat(mViewHolder.mTwoLineTitleText.getVisibility()).isEqualTo(View.VISIBLE);
|
||||||
|
assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE);
|
||||||
|
assertThat(mViewHolder.mTwoLineTitleText.getText()).isEqualTo(TEST_DEVICE_NAME_1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onBindViewHolder_bindDisconnectedBluetoothDevice_verifyView() {
|
||||||
|
when(mMediaDevice2.getDeviceType()).thenReturn(
|
||||||
|
MediaDevice.MediaDeviceType.TYPE_BLUETOOTH_DEVICE);
|
||||||
|
when(mMediaDevice2.isConnected()).thenReturn(false);
|
||||||
|
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 1);
|
||||||
|
|
||||||
|
assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.GONE);
|
||||||
|
assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE);
|
||||||
|
assertThat(mViewHolder.mTitleText.getText().toString()).isEqualTo(
|
||||||
|
mContext.getString(R.string.media_output_dialog_disconnected, TEST_DEVICE_NAME_2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onBindViewHolder_bindFailedStateDevice_verifyView() {
|
||||||
|
when(mMediaDevice2.getState()).thenReturn(
|
||||||
|
LocalMediaManager.MediaDeviceState.STATE_CONNECTING_FAILED);
|
||||||
|
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 1);
|
||||||
|
|
||||||
|
assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
|
||||||
|
assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.GONE);
|
||||||
|
assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
|
||||||
|
assertThat(mViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.VISIBLE);
|
||||||
|
assertThat(mViewHolder.mTwoLineTitleText.getVisibility()).isEqualTo(View.VISIBLE);
|
||||||
|
assertThat(mViewHolder.mSubTitleText.getText()).isEqualTo(mContext.getText(
|
||||||
|
R.string.media_output_dialog_connect_failed));
|
||||||
|
assertThat(mViewHolder.mTwoLineTitleText.getText()).isEqualTo(TEST_DEVICE_NAME_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onBindViewHolder_inTransferring_bindTransferringDevice_verifyView() {
|
||||||
|
when(mMediaOutputController.isTransferring()).thenReturn(true);
|
||||||
|
when(mMediaDevice1.getState()).thenReturn(
|
||||||
|
LocalMediaManager.MediaDeviceState.STATE_CONNECTING);
|
||||||
|
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
|
||||||
|
|
||||||
|
assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
|
||||||
|
assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.GONE);
|
||||||
|
assertThat(mViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE);
|
||||||
|
assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.VISIBLE);
|
||||||
|
assertThat(mViewHolder.mTwoLineTitleText.getVisibility()).isEqualTo(View.VISIBLE);
|
||||||
|
assertThat(mViewHolder.mTwoLineTitleText.getText()).isEqualTo(TEST_DEVICE_NAME_1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onBindViewHolder_inTransferring_bindNonTransferringDevice_verifyView() {
|
||||||
|
when(mMediaOutputController.isTransferring()).thenReturn(true);
|
||||||
|
when(mMediaDevice2.getState()).thenReturn(
|
||||||
|
LocalMediaManager.MediaDeviceState.STATE_CONNECTING);
|
||||||
|
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
|
||||||
|
|
||||||
|
assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE);
|
||||||
|
assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.GONE);
|
||||||
|
assertThat(mViewHolder.mTitleText.getText()).isEqualTo(TEST_DEVICE_NAME_1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onItemClick_clickPairNew_verifyLaunchBluetoothPairing() {
|
||||||
|
when(mMediaOutputController.isZeroMode()).thenReturn(true);
|
||||||
|
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 2);
|
||||||
|
mViewHolder.mFrameLayout.performClick();
|
||||||
|
|
||||||
|
verify(mMediaOutputController).launchBluetoothPairing();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onItemClick_clickDevice_verifyConnectDevice() {
|
||||||
|
assertThat(mMediaDevice2.getState()).isEqualTo(
|
||||||
|
LocalMediaManager.MediaDeviceState.STATE_DISCONNECTED);
|
||||||
|
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 1);
|
||||||
|
mViewHolder.mFrameLayout.performClick();
|
||||||
|
|
||||||
|
verify(mMediaOutputController).connectDevice(mMediaDevice2);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user