Merge "[Audiosharing] Add audio sharing dialog." into main

This commit is contained in:
Yiyi Shen
2023-11-01 03:54:45 +00:00
committed by Android (Google) Code Review
6 changed files with 284 additions and 4 deletions

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2023 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
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/device_button"
android:overScrollMode="never"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="center"
android:text=""/>
</FrameLayout>

View File

@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2023 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="24dp"
android:orientation="vertical">
<TextView
style="@style/device_info_dialog_value"
android:id="@+id/share_audio_subtitle1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="center"
android:layout_gravity="center"/>
<TextView
style="@style/device_info_dialog_value"
android:id="@+id/share_audio_subtitle2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="center"
android:layout_gravity="center"/>
<com.android.internal.widget.RecyclerView
android:visibility="visible"
android:id="@+id/btn_list"
android:nestedScrollingEnabled="false"
android:overScrollMode="never"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"/>
</LinearLayout>

View File

@@ -75,6 +75,8 @@ public class AudioSharingDashboardFragment extends DashboardFragment {
mMainSwitchBar = activity.getSwitchBar();
mMainSwitchBar.setTitle(getText(R.string.audio_sharing_switch_title));
mSwitchBarController = new AudioSharingSwitchBarController(activity, mMainSwitchBar);
mSwitchBarController.init(this);
getSettingsLifecycle().addObserver(mSwitchBarController);
mMainSwitchBar.show();
}
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright (C) 2023 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.settings.connecteddevice.audiosharing;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import com.android.internal.widget.RecyclerView;
import com.android.settings.R;
import java.util.ArrayList;
public class AudioSharingDeviceAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final String TAG = "AudioSharingDeviceAdapter";
private final ArrayList<String> mDevices;
private final OnClickListener mOnClickListener;
public AudioSharingDeviceAdapter(ArrayList<String> devices, OnClickListener listener) {
mDevices = devices;
mOnClickListener = listener;
}
private class AudioSharingDeviceViewHolder extends RecyclerView.ViewHolder {
private final Button mButtonView;
AudioSharingDeviceViewHolder(View view) {
super(view);
mButtonView = view.findViewById(R.id.device_button);
}
public void bindView(int position) {
if (mButtonView != null) {
mButtonView.setText(mDevices.get(position));
mButtonView.setOnClickListener(v -> mOnClickListener.onClick(position));
} else {
Log.w(TAG, "bind view skipped due to button view is null");
}
}
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view =
LayoutInflater.from(parent.getContext())
.inflate(R.layout.audio_sharing_device_item, parent, false);
return new AudioSharingDeviceViewHolder(view);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
((AudioSharingDeviceViewHolder) holder).bindView(position);
}
@Override
public int getItemCount() {
return mDevices.size();
}
public interface OnClickListener {
/** Called when an item has been clicked. */
void onClick(int position);
}
}

View File

@@ -0,0 +1,89 @@
/*
* Copyright (C) 2023 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.settings.connecteddevice.audiosharing;
import android.app.Dialog;
import android.app.settings.SettingsEnums;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import com.android.internal.widget.LinearLayoutManager;
import com.android.internal.widget.RecyclerView;
import com.android.settings.R;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.flags.Flags;
import java.util.ArrayList;
public class AudioSharingDialogFragment extends InstrumentedDialogFragment {
private static final String TAG = "AudioSharingDialog";
private View mRootView;
@Override
public int getMetricsCategory() {
return SettingsEnums.DIALOG_START_AUDIO_SHARING;
}
/**
* Display the {@link AudioSharingDialogFragment} dialog.
*
* @param host The Fragment this dialog will be hosted.
*/
public static void show(Fragment host) {
if (!Flags.enableLeAudioSharing()) return;
final FragmentManager manager = host.getChildFragmentManager();
if (manager.findFragmentByTag(TAG) == null) {
final AudioSharingDialogFragment dialog = new AudioSharingDialogFragment();
dialog.show(manager, TAG);
}
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final AlertDialog.Builder builder =
new AlertDialog.Builder(getActivity()).setTitle("Share audio");
mRootView =
LayoutInflater.from(builder.getContext())
.inflate(R.layout.dialog_audio_sharing, /* parent= */ null);
// TODO: use real subtitle according to device count.
TextView subTitle1 = mRootView.findViewById(R.id.share_audio_subtitle1);
TextView subTitle2 = mRootView.findViewById(R.id.share_audio_subtitle2);
subTitle1.setText("2 devices connected");
subTitle2.setText("placeholder");
RecyclerView recyclerView = mRootView.findViewById(R.id.btn_list);
// TODO: use real audio sharing device list.
ArrayList<String> devices = new ArrayList<>();
devices.add("Buds 1");
devices.add("Buds 2");
recyclerView.setAdapter(
new AudioSharingDeviceAdapter(
devices,
(int position) -> {
// TODO: add on click callback.
}));
recyclerView.setLayoutManager(
new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
return builder.setView(mRootView).create();
}
}

View File

@@ -17,24 +17,30 @@
package com.android.settings.connecteddevice.audiosharing;
import android.content.Context;
import android.util.Log;
import android.widget.Switch;
import androidx.annotation.NonNull;
import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.flags.Flags;
import com.android.settings.widget.SettingsMainSwitchBar;
import com.android.settingslib.widget.OnMainSwitchChangeListener;
public class AudioSharingSwitchBarController
public class AudioSharingSwitchBarController extends BasePreferenceController
implements DefaultLifecycleObserver, OnMainSwitchChangeListener {
private static final String TAG = "AudioSharingSwitchBarCtl";
private static final String PREF_KEY = "audio_sharing_main_switch";
private final Context mContext;
private final SettingsMainSwitchBar mSwitchBar;
private DashboardFragment mFragment;
AudioSharingSwitchBarController(Context context, SettingsMainSwitchBar switchBar) {
super(context, PREF_KEY);
mContext = context;
mSwitchBar = switchBar;
mSwitchBar.setChecked(false);
@@ -54,11 +60,32 @@ public class AudioSharingSwitchBarController
public void onSwitchChanged(Switch switchView, boolean isChecked) {
// Filter out unnecessary callbacks when switch is disabled.
if (!switchView.isEnabled()) return;
if (isChecked) {
// TODO: start sharing
startAudioSharing();
} else {
// TODO: stop sharing
}
}
@Override
public int getAvailabilityStatus() {
return Flags.enableLeAudioSharing() ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
}
/**
* Initialize the controller.
*
* @param fragment The fragment to host the {@link AudioSharingSwitchBarController} dialog.
*/
public void init(DashboardFragment fragment) {
this.mFragment = fragment;
}
private void startAudioSharing() {
if (mFragment != null) {
AudioSharingDialogFragment.show(mFragment);
} else {
Log.w(TAG, "Dialog fail to show due to null fragment.");
}
}
}