diff options
author | timhypeng <timhypeng@google.com> | 2020-09-07 14:24:09 +0800 |
---|---|---|
committer | tim peng <timhypeng@google.com> | 2020-12-02 03:20:51 +0000 |
commit | d04087aff36e12759e932e8b12046a006455f613 (patch) | |
tree | d20d689784106e25d652615304df261bbc9e8448 /packages/SystemUI/src | |
parent | 2f172d225c9243421f1e70bb36f9f94a612495c8 (diff) |
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
Diffstat (limited to 'packages/SystemUI/src')
-rw-r--r-- | packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java | 163 | ||||
-rw-r--r-- | packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java | 165 |
2 files changed, 328 insertions, 0 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java new file mode 100644 index 000000000000..9fc64d51cdf7 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java @@ -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)); + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java new file mode 100644 index 000000000000..7579c25b030a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java @@ -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; + } + }); + } + } +} |