Add Volume panel
Volume panel hosts each volume stream, including: - Media volume - Call Volume - Ring volume - Alarm volume Change-Id: I1801d10d2304c57615e9499386c638c74ffcd7c3 Screenshot: https://screenshot.googleplex.com/m764j65ECto Bug: 117804161 Test: Manual app Test: robolectric
This commit is contained in:
@@ -10233,6 +10233,9 @@
|
|||||||
<!-- Title for the Internet Connectivity dialog (settings panel) with Internet related settings [CHAR LIMIT=50] -->
|
<!-- Title for the Internet Connectivity dialog (settings panel) with Internet related settings [CHAR LIMIT=50] -->
|
||||||
<string name="internet_connectivity_panel_title">Internet Connectivity</string>
|
<string name="internet_connectivity_panel_title">Internet Connectivity</string>
|
||||||
|
|
||||||
|
<!-- Title for the Volume dialog (settings panel) with all volume streams[CHAR LIMIT=50] -->
|
||||||
|
<string name="volume_connectivity_panel_title">Volume</string>
|
||||||
|
|
||||||
<!-- UI debug setting: force desktop mode [CHAR LIMIT=50] -->
|
<!-- UI debug setting: force desktop mode [CHAR LIMIT=50] -->
|
||||||
<string name="force_desktop_mode">Force desktop mode</string>
|
<string name="force_desktop_mode">Force desktop mode</string>
|
||||||
<!-- UI debug setting: force desktop mode summary [CHAR LIMIT=NONE] -->
|
<!-- UI debug setting: force desktop mode summary [CHAR LIMIT=NONE] -->
|
||||||
|
@@ -28,6 +28,7 @@
|
|||||||
android:icon="@drawable/ic_media_stream"
|
android:icon="@drawable/ic_media_stream"
|
||||||
android:title="@string/media_volume_option_title"
|
android:title="@string/media_volume_option_title"
|
||||||
android:order="-180"
|
android:order="-180"
|
||||||
|
settings:allowDynamicSummaryInSlice="true"
|
||||||
settings:controller="com.android.settings.notification.MediaVolumePreferenceController"/>
|
settings:controller="com.android.settings.notification.MediaVolumePreferenceController"/>
|
||||||
|
|
||||||
<!-- Media output switcher -->
|
<!-- Media output switcher -->
|
||||||
@@ -44,6 +45,7 @@
|
|||||||
android:icon="@drawable/ic_local_phone_24_lib"
|
android:icon="@drawable/ic_local_phone_24_lib"
|
||||||
android:title="@string/call_volume_option_title"
|
android:title="@string/call_volume_option_title"
|
||||||
android:order="-170"
|
android:order="-170"
|
||||||
|
settings:allowDynamicSummaryInSlice="true"
|
||||||
settings:controller="com.android.settings.notification.CallVolumePreferenceController"/>
|
settings:controller="com.android.settings.notification.CallVolumePreferenceController"/>
|
||||||
|
|
||||||
<!-- Hands free profile output switcher -->
|
<!-- Hands free profile output switcher -->
|
||||||
@@ -60,6 +62,7 @@
|
|||||||
android:icon="@drawable/ic_notifications"
|
android:icon="@drawable/ic_notifications"
|
||||||
android:title="@string/ring_volume_option_title"
|
android:title="@string/ring_volume_option_title"
|
||||||
android:order="-160"
|
android:order="-160"
|
||||||
|
settings:allowDynamicSummaryInSlice="true"
|
||||||
settings:controller="com.android.settings.notification.RingVolumePreferenceController"/>
|
settings:controller="com.android.settings.notification.RingVolumePreferenceController"/>
|
||||||
|
|
||||||
|
|
||||||
@@ -69,6 +72,7 @@
|
|||||||
android:icon="@*android:drawable/ic_audio_alarm"
|
android:icon="@*android:drawable/ic_audio_alarm"
|
||||||
android:title="@string/alarm_volume_option_title"
|
android:title="@string/alarm_volume_option_title"
|
||||||
android:order="-150"
|
android:order="-150"
|
||||||
|
settings:allowDynamicSummaryInSlice="true"
|
||||||
settings:controller="com.android.settings.notification.AlarmVolumePreferenceController"/>
|
settings:controller="com.android.settings.notification.AlarmVolumePreferenceController"/>
|
||||||
|
|
||||||
<!-- Notification volume -->
|
<!-- Notification volume -->
|
||||||
|
@@ -47,8 +47,8 @@ public class InternetConnectivityPanel implements PanelContent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getTitle() {
|
public CharSequence getTitle() {
|
||||||
return (String) mContext.getText(R.string.internet_connectivity_panel_title);
|
return mContext.getText(R.string.internet_connectivity_panel_title);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -25,6 +25,8 @@ public class PanelFeatureProviderImpl implements PanelFeatureProvider {
|
|||||||
switch (panelType) {
|
switch (panelType) {
|
||||||
case SettingsPanelActivity.PANEL_TYPE_WIFI:
|
case SettingsPanelActivity.PANEL_TYPE_WIFI:
|
||||||
return InternetConnectivityPanel.create(context);
|
return InternetConnectivityPanel.create(context);
|
||||||
|
case SettingsPanelActivity.PANEL_TYPE_VOLUME:
|
||||||
|
return VolumePanel.create(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new IllegalStateException("No matching panel for: " + panelType);
|
throw new IllegalStateException("No matching panel for: " + panelType);
|
||||||
|
@@ -54,6 +54,9 @@ public class SettingsPanelActivity extends FragmentActivity {
|
|||||||
// TODO (b/117804442) move to framework
|
// TODO (b/117804442) move to framework
|
||||||
public static final String PANEL_TYPE_WIFI = "wifi_panel";
|
public static final String PANEL_TYPE_WIFI = "wifi_panel";
|
||||||
|
|
||||||
|
// TODO (b/117804442) move to framework
|
||||||
|
public static final String PANEL_TYPE_VOLUME = "volume_panel";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
64
src/com/android/settings/panel/VolumePanel.java
Normal file
64
src/com/android/settings/panel/VolumePanel.java
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 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.panel;
|
||||||
|
|
||||||
|
import static com.android.settings.slices.CustomSliceRegistry.VOLUME_ALARM_URI;
|
||||||
|
import static com.android.settings.slices.CustomSliceRegistry.VOLUME_CALL_URI;
|
||||||
|
import static com.android.settings.slices.CustomSliceRegistry.VOLUME_MEDIA_URI;
|
||||||
|
import static com.android.settings.slices.CustomSliceRegistry.VOLUME_RINGER_URI;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.provider.Settings;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class VolumePanel implements PanelContent {
|
||||||
|
|
||||||
|
private final Context mContext;
|
||||||
|
|
||||||
|
public static VolumePanel create(Context context) {
|
||||||
|
return new VolumePanel(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
private VolumePanel(Context context) {
|
||||||
|
mContext = context.getApplicationContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CharSequence getTitle() {
|
||||||
|
return mContext.getText(R.string.volume_connectivity_panel_title);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Uri> getSlices() {
|
||||||
|
final List<Uri> uris = new ArrayList<>();
|
||||||
|
uris.add(VOLUME_MEDIA_URI);
|
||||||
|
uris.add(VOLUME_CALL_URI);
|
||||||
|
uris.add(VOLUME_RINGER_URI);
|
||||||
|
uris.add(VOLUME_ALARM_URI);
|
||||||
|
return uris;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Intent getSeeMoreIntent() {
|
||||||
|
return new Intent(Settings.ACTION_SOUND_SETTINGS);
|
||||||
|
}
|
||||||
|
}
|
@@ -25,6 +25,7 @@ import android.content.ContentResolver;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.provider.SettingsSlicesContract;
|
import android.provider.SettingsSlicesContract;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController;
|
import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController;
|
||||||
import com.android.settings.wifi.calling.WifiCallingSliceHelper;
|
import com.android.settings.wifi.calling.WifiCallingSliceHelper;
|
||||||
|
|
||||||
@@ -147,6 +148,43 @@ public class CustomSliceRegistry {
|
|||||||
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
|
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
|
||||||
.appendPath("storage_card")
|
.appendPath("storage_card")
|
||||||
.build();
|
.build();
|
||||||
|
/**
|
||||||
|
* Full {@link Uri} for the Alarm volume Slice.
|
||||||
|
*/
|
||||||
|
public static final Uri VOLUME_ALARM_URI = new Uri.Builder()
|
||||||
|
.scheme(ContentResolver.SCHEME_CONTENT)
|
||||||
|
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
|
||||||
|
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
|
||||||
|
.appendPath("alarm_volume")
|
||||||
|
.build();
|
||||||
|
/**
|
||||||
|
* Full {@link Uri} for the Call Volume Slice.
|
||||||
|
*/
|
||||||
|
public static final Uri VOLUME_CALL_URI = new Uri.Builder()
|
||||||
|
.scheme(ContentResolver.SCHEME_CONTENT)
|
||||||
|
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
|
||||||
|
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
|
||||||
|
.appendPath("call_volume")
|
||||||
|
.build();
|
||||||
|
/**
|
||||||
|
* Full {@link Uri} for the Media Volume Slice.
|
||||||
|
*/
|
||||||
|
public static final Uri VOLUME_MEDIA_URI = new Uri.Builder()
|
||||||
|
.scheme(ContentResolver.SCHEME_CONTENT)
|
||||||
|
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
|
||||||
|
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
|
||||||
|
.appendPath("media_volume")
|
||||||
|
.build();
|
||||||
|
/**
|
||||||
|
* Full {@link Uri} for the Ringer volume Slice.
|
||||||
|
*/
|
||||||
|
public static final Uri VOLUME_RINGER_URI = new Uri.Builder()
|
||||||
|
.scheme(ContentResolver.SCHEME_CONTENT)
|
||||||
|
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
|
||||||
|
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
|
||||||
|
.appendPath("ring_volume")
|
||||||
|
.build();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Full {@link Uri} for the Wifi Calling Slice.
|
* Full {@link Uri} for the Wifi Calling Slice.
|
||||||
*/
|
*/
|
||||||
|
@@ -193,8 +193,9 @@ public class SliceBuilderUtils {
|
|||||||
CharSequence summaryText = controller.getSummary();
|
CharSequence summaryText = controller.getSummary();
|
||||||
|
|
||||||
// Priority 1 : User prefers showing the dynamic summary in slice view rather than static
|
// Priority 1 : User prefers showing the dynamic summary in slice view rather than static
|
||||||
// summary.
|
// summary. Note it doesn't require a valid summary - so we can force some slices to have
|
||||||
if (isDynamicSummaryAllowed && isValidSummary(context, summaryText)) {
|
// empty summaries (ex: volume).
|
||||||
|
if (isDynamicSummaryAllowed) {
|
||||||
return summaryText;
|
return summaryText;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -61,7 +61,6 @@ public class PanelFragmentTest {
|
|||||||
mFakePanelContent = new FakePanelContent();
|
mFakePanelContent = new FakePanelContent();
|
||||||
doReturn(mFakePanelContent).when(mPanelFeatureProvider).getPanel(any(), any());
|
doReturn(mFakePanelContent).when(mPanelFeatureProvider).getPanel(any(), any());
|
||||||
|
|
||||||
|
|
||||||
ActivityController<FakeSettingsPanelActivity> activityController =
|
ActivityController<FakeSettingsPanelActivity> activityController =
|
||||||
Robolectric.buildActivity(FakeSettingsPanelActivity.class);
|
Robolectric.buildActivity(FakeSettingsPanelActivity.class);
|
||||||
activityController.setup();
|
activityController.setup();
|
||||||
|
@@ -54,7 +54,13 @@ public class PanelSlicesAdapterTest {
|
|||||||
public void setUp() {
|
public void setUp() {
|
||||||
mContext = RuntimeEnvironment.application;
|
mContext = RuntimeEnvironment.application;
|
||||||
|
|
||||||
final ActivityController<FakeSettingsPanelActivity> activityController =
|
mPanelFeatureProvider = spy(new PanelFeatureProviderImpl());
|
||||||
|
mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
|
||||||
|
mFakeFeatureFactory.panelFeatureProvider = mPanelFeatureProvider;
|
||||||
|
mFakePanelContent = new FakePanelContent();
|
||||||
|
doReturn(mFakePanelContent).when(mPanelFeatureProvider).getPanel(any(), any());
|
||||||
|
|
||||||
|
ActivityController<FakeSettingsPanelActivity> activityController =
|
||||||
Robolectric.buildActivity(FakeSettingsPanelActivity.class);
|
Robolectric.buildActivity(FakeSettingsPanelActivity.class);
|
||||||
activityController.setup();
|
activityController.setup();
|
||||||
|
|
||||||
@@ -65,12 +71,6 @@ public class PanelSlicesAdapterTest {
|
|||||||
.getSupportFragmentManager()
|
.getSupportFragmentManager()
|
||||||
.findFragmentById(R.id.main_content));
|
.findFragmentById(R.id.main_content));
|
||||||
|
|
||||||
mPanelFeatureProvider = spy(new PanelFeatureProviderImpl());
|
|
||||||
mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
|
|
||||||
mFakeFeatureFactory.panelFeatureProvider = mPanelFeatureProvider;
|
|
||||||
mFakePanelContent = new FakePanelContent();
|
|
||||||
doReturn(mFakePanelContent).when(mPanelFeatureProvider).getPanel(any(), any());
|
|
||||||
|
|
||||||
mAdapter = new PanelSlicesAdapter(mPanelFragment, mFakePanelContent.getSlices());
|
mAdapter = new PanelSlicesAdapter(mPanelFragment, mFakePanelContent.getSlices());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 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.panel;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
|
import com.android.settings.slices.CustomSliceRegistry;
|
||||||
|
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
|
public class VolumePanelTest {
|
||||||
|
|
||||||
|
private VolumePanel mPanel;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
mPanel = VolumePanel.create(RuntimeEnvironment.application);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getSlices_containsNecessarySlices() {
|
||||||
|
final List<Uri> uris = mPanel.getSlices();
|
||||||
|
|
||||||
|
assertThat(uris).containsExactly(
|
||||||
|
CustomSliceRegistry.VOLUME_CALL_URI,
|
||||||
|
CustomSliceRegistry.VOLUME_MEDIA_URI,
|
||||||
|
CustomSliceRegistry.VOLUME_RINGER_URI,
|
||||||
|
CustomSliceRegistry.VOLUME_ALARM_URI);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getSeeMoreIntent_notNull() {
|
||||||
|
assertThat(mPanel.getSeeMoreIntent()).isNotNull();
|
||||||
|
}
|
||||||
|
}
|
@@ -217,6 +217,19 @@ public class SliceBuilderUtilsTest {
|
|||||||
assertThat(summary).isEqualTo(controllerSummary);
|
assertThat(summary).isEqualTo(controllerSummary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getDynamicSummary_allowDynamicSummary_nullSummary_returnsNull() {
|
||||||
|
final SliceData data = getDummyData(true /*isDynamicSummaryAllowed*/);
|
||||||
|
final FakePreferenceController controller = spy(
|
||||||
|
new FakePreferenceController(mContext, KEY));
|
||||||
|
final String controllerSummary = null;
|
||||||
|
doReturn(controllerSummary).when(controller).getSummary();
|
||||||
|
|
||||||
|
final CharSequence summary = SliceBuilderUtils.getSubtitleText(mContext, controller, data);
|
||||||
|
|
||||||
|
assertThat(summary).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getDynamicSummary_returnsScreenTitle() {
|
public void getDynamicSummary_returnsScreenTitle() {
|
||||||
final SliceData data = getDummyData();
|
final SliceData data = getDummyData();
|
||||||
|
Reference in New Issue
Block a user