| /* |
| * 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.TextUtils; |
| 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 boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); |
| |
| private ViewGroup mConnectedItem; |
| private boolean mInclueDynamicGroup; |
| |
| 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) { |
| final int size = mController.getMediaDevices().size(); |
| if (position == size && mController.isZeroMode()) { |
| viewHolder.onBind(CUSTOMIZED_ITEM_PAIR_NEW, false /* topMargin */, |
| true /* bottomMargin */); |
| } else if (mInclueDynamicGroup) { |
| if (position == 0) { |
| viewHolder.onBind(CUSTOMIZED_ITEM_DYNAMIC_GROUP, true /* topMargin */, |
| false /* bottomMargin */); |
| } else { |
| // When group item is added at the first(position == 0), devices will be added from |
| // the second item(position == 1). It means that the index of device list starts |
| // from "position - 1". |
| viewHolder.onBind(((List<MediaDevice>) (mController.getMediaDevices())) |
| .get(position - 1), |
| false /* topMargin */, position == size /* bottomMargin */); |
| } |
| } else if (position < size) { |
| viewHolder.onBind(((List<MediaDevice>) (mController.getMediaDevices())).get(position), |
| position == 0 /* topMargin */, position == (size - 1) /* bottomMargin */); |
| } else if (DEBUG) { |
| Log.d(TAG, "Incorrect position: " + position); |
| } |
| } |
| |
| @Override |
| public int getItemCount() { |
| mInclueDynamicGroup = mController.getSelectedMediaDevice().size() > 1; |
| if (mController.isZeroMode() || mInclueDynamicGroup) { |
| // Add extra one for "pair new" or dynamic group |
| return mController.getMediaDevices().size() + 1; |
| } |
| return mController.getMediaDevices().size(); |
| } |
| |
| @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, boolean topMargin, boolean bottomMargin) { |
| super.onBind(device, topMargin, bottomMargin); |
| final boolean currentlyConnected = !mInclueDynamicGroup && isCurrentlyConnected(device); |
| if (currentlyConnected) { |
| mConnectedItem = mContainerLayout; |
| } |
| mBottomDivider.setVisibility(View.GONE); |
| mCheckBox.setVisibility(View.GONE); |
| if (currentlyConnected && mController.isActiveRemoteDevice(device)) { |
| // Init active device layout |
| mDivider.setVisibility(View.VISIBLE); |
| mDivider.setTransitionAlpha(1); |
| mAddIcon.setVisibility(View.VISIBLE); |
| mAddIcon.setTransitionAlpha(1); |
| mAddIcon.setOnClickListener(v -> onEndItemClick()); |
| } else { |
| // Init non-active device layout |
| mDivider.setVisibility(View.GONE); |
| mAddIcon.setVisibility(View.GONE); |
| } |
| if (mController.isTransferring()) { |
| if (device.getState() == MediaDeviceState.STATE_CONNECTING |
| && !mController.hasAdjustVolumeUserRestriction()) { |
| setTwoLineLayout(device, true /* bFocused */, false /* showSeekBar*/, |
| true /* showProgressBar */, false /* showSubtitle */); |
| } else { |
| setSingleLineLayout(getItemTitle(device), false /* bFocused */); |
| } |
| } else { |
| // Set different layout for each device |
| if (device.getState() == MediaDeviceState.STATE_CONNECTING_FAILED) { |
| setTwoLineLayout(device, false /* bFocused */, |
| false /* showSeekBar */, false /* showProgressBar */, |
| true /* showSubtitle */); |
| mSubTitleText.setText(R.string.media_output_dialog_connect_failed); |
| mContainerLayout.setOnClickListener(v -> onItemClick(v, device)); |
| } else if (!mController.hasAdjustVolumeUserRestriction() && currentlyConnected) { |
| setTwoLineLayout(device, true /* bFocused */, true /* showSeekBar */, |
| false /* showProgressBar */, false /* showSubtitle */); |
| initSeekbar(device); |
| } else { |
| setSingleLineLayout(getItemTitle(device), false /* bFocused */); |
| mContainerLayout.setOnClickListener(v -> onItemClick(v, device)); |
| } |
| } |
| } |
| |
| @Override |
| void onBind(int customizedItem, boolean topMargin, boolean bottomMargin) { |
| super.onBind(customizedItem, topMargin, bottomMargin); |
| if (customizedItem == CUSTOMIZED_ITEM_PAIR_NEW) { |
| mCheckBox.setVisibility(View.GONE); |
| mDivider.setVisibility(View.GONE); |
| mAddIcon.setVisibility(View.GONE); |
| mBottomDivider.setVisibility(View.GONE); |
| setSingleLineLayout(mContext.getText(R.string.media_output_dialog_pairing_new), |
| false /* bFocused */); |
| final Drawable d = mContext.getDrawable(R.drawable.ic_add); |
| d.setColorFilter(new PorterDuffColorFilter( |
| Utils.getColorAccentDefaultColor(mContext), PorterDuff.Mode.SRC_IN)); |
| mTitleIcon.setImageDrawable(d); |
| mContainerLayout.setOnClickListener(v -> onItemClick(CUSTOMIZED_ITEM_PAIR_NEW)); |
| } else if (customizedItem == CUSTOMIZED_ITEM_DYNAMIC_GROUP) { |
| mConnectedItem = mContainerLayout; |
| mBottomDivider.setVisibility(View.GONE); |
| mCheckBox.setVisibility(View.GONE); |
| mDivider.setVisibility(View.VISIBLE); |
| mDivider.setTransitionAlpha(1); |
| mAddIcon.setVisibility(View.VISIBLE); |
| mAddIcon.setTransitionAlpha(1); |
| mAddIcon.setOnClickListener(v -> onEndItemClick()); |
| mTitleIcon.setImageDrawable(getSpeakerDrawable()); |
| final CharSequence sessionName = mController.getSessionName(); |
| final CharSequence title = TextUtils.isEmpty(sessionName) |
| ? mContext.getString(R.string.media_output_dialog_group) : sessionName; |
| setTwoLineLayout(title, true /* bFocused */, true /* showSeekBar */, |
| false /* showProgressBar */, false /* showSubtitle */); |
| initSessionSeekbar(); |
| } |
| } |
| |
| private void onItemClick(View view, MediaDevice device) { |
| if (mController.isTransferring()) { |
| return; |
| } |
| |
| playSwitchingAnim(mConnectedItem, view); |
| mController.connectDevice(device); |
| device.setState(MediaDeviceState.STATE_CONNECTING); |
| if (!isAnimating()) { |
| notifyDataSetChanged(); |
| } |
| } |
| |
| private void onItemClick(int customizedItem) { |
| if (customizedItem == CUSTOMIZED_ITEM_PAIR_NEW) { |
| mController.launchBluetoothPairing(); |
| } |
| } |
| |
| private void onEndItemClick() { |
| mController.launchMediaOutputGroupDialog(); |
| } |
| } |
| } |