summaryrefslogtreecommitdiff
path: root/packages/SystemUI/src
diff options
context:
space:
mode:
authortimhypeng <timhypeng@google.com>2020-09-07 14:24:09 +0800
committertim peng <timhypeng@google.com>2020-12-02 03:20:51 +0000
commitd04087aff36e12759e932e8b12046a006455f613 (patch)
treed20d689784106e25d652615304df261bbc9e8448 /packages/SystemUI/src
parent2f172d225c9243421f1e70bb36f9f94a612495c8 (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.java163
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java165
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;
+ }
+ });
+ }
+ }
+}