diff options
15 files changed, 174 insertions, 1382 deletions
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java index 4b3afdc3eb7a..6c31b2af039e 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java @@ -181,6 +181,5 @@ public interface VolumeDialogController { void onScreenOff(); void onShowSafetyWarning(int flags); void onAccessibilityModeChanged(Boolean showA11yStream); - void onConnectedDeviceChanged(String deviceName); } } diff --git a/packages/SystemUI/res/drawable/rounded_bg_bottom_background.xml b/packages/SystemUI/res/drawable/rounded_bg_bottom_background.xml new file mode 100644 index 000000000000..8d03ce77f139 --- /dev/null +++ b/packages/SystemUI/res/drawable/rounded_bg_bottom_background.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <solid android:color="@*android:color/material_grey_200" /> + <corners + android:bottomLeftRadius="@dimen/corner_size" + android:topLeftRadius="0dp" + android:bottomRightRadius="@dimen/corner_size" + android:topRightRadius="0dp" + /> +</shape> diff --git a/packages/SystemUI/res/layout/output_chooser.xml b/packages/SystemUI/res/layout/output_chooser.xml deleted file mode 100644 index b9f7b152ecac..000000000000 --- a/packages/SystemUI/res/layout/output_chooser.xml +++ /dev/null @@ -1,70 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - Copyright (C) 2017 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. ---> -<!-- extends LinearLayout --> -<com.android.systemui.HardwareUiLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_marginBottom="0dp" - android:clipToPadding="false" - android:theme="@style/qs_theme" - android:clipChildren="false"> - <com.android.systemui.volume.OutputChooserLayout - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:sysui="http://schemas.android.com/apk/res-auto" - android:id="@+id/output_chooser" - android:layout_width="@dimen/output_chooser_panel_width" - android:layout_height="@dimen/output_chooser_panel_width" - android:layout_gravity="center_vertical|end" - android:orientation="vertical" - android:translationZ="8dp" - android:padding="20dp" > - - <TextView - android:id="@+id/title" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textDirection="locale" - android:textAppearance="@style/TextAppearance.QS.DetailHeader" - android:layout_marginBottom="20dp" /> - - <com.android.systemui.qs.AutoSizingList - android:id="@android:id/list" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical" - sysui:itemHeight="@dimen/qs_detail_item_height" - style="@style/AutoSizingList"/> - - <LinearLayout - android:id="@android:id/empty" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_gravity="center" - android:gravity="center" - android:orientation="vertical"> - - <TextView - android:id="@+id/empty_text" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textDirection="locale" - android:layout_marginTop="20dp" - android:textAppearance="@style/TextAppearance.QS.DetailEmpty"/> - </LinearLayout> - </com.android.systemui.volume.OutputChooserLayout> -</com.android.systemui.HardwareUiLayout> diff --git a/packages/SystemUI/res/layout/output_chooser_item.xml b/packages/SystemUI/res/layout/output_chooser_item.xml deleted file mode 100644 index c3ddbbe83dd7..000000000000 --- a/packages/SystemUI/res/layout/output_chooser_item.xml +++ /dev/null @@ -1,72 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - Copyright (C) 2017 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:minHeight="@dimen/qs_detail_item_height" - android:background="@drawable/btn_borderless_rect" - android:clickable="true" - android:focusable="true" - android:gravity="center_vertical" - android:orientation="horizontal" > - - <ImageView - android:id="@android:id/icon" - android:layout_width="@dimen/qs_detail_item_icon_width" - android:layout_height="@dimen/qs_detail_item_icon_size" - android:layout_marginStart="@dimen/qs_detail_item_icon_marginStart" - android:layout_marginEnd="@dimen/qs_detail_item_icon_marginEnd" - android:background="?android:selectableItemBackgroundBorderless" - android:tint="?android:attr/textColorPrimary"/> - - <LinearLayout - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_marginStart="12dp" - android:layout_weight="1" - android:orientation="vertical" > - - <TextView - android:id="@android:id/title" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:textDirection="locale" - android:ellipsize="end" - android:textAppearance="@style/TextAppearance.QS.DetailItemPrimary" /> - - <TextView - android:id="@android:id/summary" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:textDirection="locale" - android:layout_marginTop="2dp" - android:textAppearance="@style/TextAppearance.QS.DetailItemSecondary" /> - </LinearLayout> - - <ImageView - android:id="@android:id/icon2" - style="@style/QSBorderlessButton" - android:layout_width="48dp" - android:layout_height="48dp" - android:layout_marginStart="30dp" - android:clickable="true" - android:focusable="true" - android:scaleType="center" - android:contentDescription="@*android:string/media_route_controller_disconnect" - android:tint="?android:attr/textColorPrimary" /> - -</LinearLayout> diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml index 803659f9c7ae..b6d241ba3f96 100644 --- a/packages/SystemUI/res/layout/volume_dialog.xml +++ b/packages/SystemUI/res/layout/volume_dialog.xml @@ -23,79 +23,70 @@ <!-- right-aligned to be physically near volume button --> <LinearLayout android:id="@+id/volume_dialog" + android:minWidth="@dimen/volume_dialog_panel_width" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical|right" - android:minWidth="@dimen/volume_dialog_panel_width" android:background="@android:color/transparent" android:layout_margin="@dimen/volume_dialog_base_margin" android:orientation="vertical" android:clipChildren="false" > + <FrameLayout + android:id="@+id/ringer" + android:layout_width="@dimen/volume_dialog_ringer_size" + android:layout_height="@dimen/volume_dialog_ringer_size" + android:layout_marginBottom="@dimen/volume_dialog_spacer" + android:elevation="@dimen/volume_panel_elevation" + android:layout_gravity="right" + android:background="@drawable/rounded_bg_full"> + <com.android.keyguard.AlphaOptimizedImageButton + android:id="@+id/ringer_icon" + style="@style/VolumeButtons" + android:background="?android:selectableItemBackgroundBorderless" + android:layout_width="@dimen/volume_dialog_tap_target_size" + android:layout_height="@dimen/volume_dialog_tap_target_size" + android:tint="@color/accent_tint_color_selector" + android:layout_gravity="center" + android:soundEffectsEnabled="false" /> + + <include layout="@layout/volume_dnd_icon"/> + </FrameLayout> + <LinearLayout - android:id="@+id/volume_dialog_rows" + android:id="@+id/main" android:layout_width="wrap_content" + android:minWidth="@dimen/volume_dialog_panel_width" android:layout_height="wrap_content" + android:orientation="vertical" android:clipChildren="false" android:clipToPadding="false" android:background="@drawable/rounded_bg_full" - android:translationZ="@dimen/volume_panel_elevation" - android:orientation="horizontal" > - <!-- volume rows added and removed here! :-) --> - </LinearLayout> - - <FrameLayout - android:id="@+id/footer" - android:layout_width="@dimen/volume_dialog_panel_width" - android:layout_height="@dimen/volume_dialog_panel_width" - android:layout_marginTop="6dp" - android:layout_marginBottom="6dp" - android:layout_below="@id/volume_dialog_rows" - android:background="@drawable/rounded_bg_full"> - + android:elevation="@dimen/volume_panel_elevation" > <LinearLayout - android:id="@+id/footer_linear_layout" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:clipChildren="false" - android:clipToPadding="false" + android:id="@+id/volume_dialog_rows" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:minWidth="@dimen/volume_dialog_panel_width" android:gravity="center" - android:layout_gravity="end" - android:translationZ="@dimen/volume_panel_elevation" - android:clickable="true" - android:orientation="vertical" > - - <TextView - android:id="@+id/ringer_title" - android:text="@string/ring_toggle_title" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:ellipsize="end" - android:maxLines="1" - android:layout_centerVertical="true" - android:textColor="?android:attr/colorControlNormal" - android:textAppearance="@style/TextAppearance.Volume.Header" /> - + android:orientation="horizontal" > + <!-- volume rows added and removed here! :-) --> + </LinearLayout> + <FrameLayout + android:layout_height="wrap_content" + android:layout_width="match_parent" + android:background="@drawable/rounded_bg_bottom_background"> <com.android.keyguard.AlphaOptimizedImageButton - android:id="@+id/ringer_icon" - style="@style/VolumeButtons" + android:id="@+id/settings" + android:src="@drawable/ic_settings" + android:layout_width="@dimen/volume_dialog_tap_target_size" + android:layout_height="@dimen/volume_dialog_tap_target_size" + android:layout_gravity="center" android:background="?android:selectableItemBackgroundBorderless" - android:layout_width="@dimen/volume_dialog_panel_width" - android:layout_height="@dimen/volume_button_size" - android:tint="@color/accent_tint_color_selector" + android:tint="#8A000000" android:soundEffectsEnabled="false" /> + </FrameLayout> + </LinearLayout> - <TextView - android:id="@+id/ringer_status" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:ellipsize="end" - android:maxLines="1" - android:textColor="?android:attr/colorControlNormal" - android:textAppearance="@style/TextAppearance.Volume.Header.Secondary" /> - </LinearLayout> - - <include layout="@layout/volume_dnd_icon"/> - </FrameLayout> </LinearLayout> </com.android.systemui.volume.VolumeUiLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/volume_dialog_row.xml b/packages/SystemUI/res/layout/volume_dialog_row.xml index fb9355ad061b..def6f6b5f701 100644 --- a/packages/SystemUI/res/layout/volume_dialog_row.xml +++ b/packages/SystemUI/res/layout/volume_dialog_row.xml @@ -18,78 +18,37 @@ android:tag="row" android:layout_height="wrap_content" android:layout_width="@dimen/volume_dialog_panel_width" - android:clipChildren="true" - android:clipToPadding="true" + android:clipChildren="false" + android:clipToPadding="false" android:theme="@style/qs_theme"> <LinearLayout - android:layout_height="match_parent" + android:layout_height="wrap_content" android:layout_width="match_parent" - android:layout_marginTop="10dp" - android:layout_marginBottom="10dp" + android:layout_marginTop="@dimen/volume_dialog_slider_margin_top" android:gravity="center" + android:layout_gravity="center" android:orientation="vertical" > - - <LinearLayout - android:orientation="vertical" + <TextView + android:id="@+id/volume_row_header" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:gravity="center" - android:padding="5dp"> - <TextView - android:id="@+id/volume_row_header" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:ellipsize="end" - android:maxLength="10" - android:maxLines="1" - android:textColor="?android:attr/colorControlNormal" - android:textAppearance="@style/TextAppearance.Volume.Header" /> - <LinearLayout - android:id="@+id/output_chooser" - android:orientation="vertical" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:minWidth="48dp" - android:minHeight="48dp" - android:paddingTop="10dp" - android:background="?android:selectableItemBackgroundBorderless" - android:gravity="center"> - <TextView - android:id="@+id/volume_row_connected_device" - android:visibility="gone" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:maxLength="10" - android:ellipsize="end" - android:maxLines="1" - android:textAppearance="@style/TextAppearance.Volume.Header.Secondary" /> - <com.android.keyguard.AlphaOptimizedImageButton - android:id="@+id/output_chooser_button" - android:layout_width="24dp" - android:layout_height="24dp" - android:background="?android:selectableItemBackgroundBorderless" - android:contentDescription="@string/accessibility_output_chooser" - style="@style/VolumeButtons" - android:clickable="false" - android:layout_centerVertical="true" - android:src="@drawable/ic_swap" - android:soundEffectsEnabled="false"/> - </LinearLayout> - </LinearLayout> + android:ellipsize="end" + android:maxLength="10" + android:maxLines="1" + android:visibility="gone" + android:textColor="?android:attr/colorControlNormal" + android:textAppearance="@style/TextAppearance.Volume.Header" /> <FrameLayout android:id="@+id/volume_row_slider_frame" - android:padding="0dp" - android:layout_width="@dimen/volume_dialog_panel_width" + android:layout_width="match_parent" android:layoutDirection="rtl" - android:layout_height="@dimen/volume_dialog_panel_width"> + android:layout_height="@dimen/volume_dialog_slider_height"> <SeekBar android:id="@+id/volume_row_slider" android:clickable="true" - android:padding="0dp" - android:layout_margin="0dp" - android:layout_width="@dimen/volume_dialog_panel_width" - android:layout_height="@dimen/volume_dialog_panel_width" + android:layout_width="@dimen/volume_dialog_slider_height" + android:layout_height="match_parent" android:layoutDirection="rtl" android:layout_gravity="center" android:rotation="90" /> @@ -98,10 +57,10 @@ <com.android.keyguard.AlphaOptimizedImageButton android:id="@+id/volume_row_icon" style="@style/VolumeButtons" - android:padding="10dp" - android:layout_width="@dimen/volume_button_size" - android:layout_height="@dimen/volume_button_size" + android:layout_width="@dimen/volume_dialog_tap_target_size" + android:layout_height="@dimen/volume_dialog_tap_target_size" android:background="?android:selectableItemBackgroundBorderless" + android:tint="@color/accent_tint_color_selector" android:soundEffectsEnabled="false" /> </LinearLayout> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 627b4bcfc104..59c009fbaddb 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -263,12 +263,22 @@ <dimen name="qs_panel_width">@dimen/notification_panel_width</dimen> <!-- the amount the volume panel should be offset at the end from the view next to it (or - the scren edge, in portrait--> - <dimen name="volume_dialog_base_margin">12dp</dimen> + the screen edge, in portrait--> + <dimen name="volume_dialog_base_margin">8dp</dimen> - <dimen name="volume_dialog_panel_width">100dp</dimen> + <dimen name="volume_dialog_panel_width">64dp</dimen> - <dimen name="output_chooser_panel_width">320dp</dimen> + <dimen name="volume_dialog_slider_height">101dp</dimen> + + <dimen name="volume_dialog_row_height">252dp</dimen> + + <dimen name="volume_dialog_ringer_size">64dp</dimen> + + <dimen name="volume_dialog_tap_target_size">48dp</dimen> + + <dimen name="volume_dialog_spacer">4dp</dimen> + + <dimen name="volume_dialog_slider_margin_top">13dp</dimen> <!-- Gravity for the notification panel --> <integer name="notification_panel_layout_gravity">0x31</integer><!-- center_horizontal|top --> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 71a3ac57f216..920dd98b400a 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1346,6 +1346,10 @@ <string name="volume_dialog_title">%s volume controls</string> + <string name="volume_dialog_ringer_guidance_vibrate">Calls and notifications will vibrate</string> + <string name="volume_dialog_ringer_guidance_silent">Calls and notifications will be muted</string> + <string name="volume_dialog_ringer_guidance_ring">Calls and notifications will ring</string> + <string name="output_title">Media output</string> <string name="output_calls_title">Phone call output</string> <string name="output_none_found">No devices found</string> diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java index 8b577400357d..ee573fbeaf33 100644 --- a/packages/SystemUI/src/com/android/systemui/Prefs.java +++ b/packages/SystemUI/src/com/android/systemui/Prefs.java @@ -30,27 +30,28 @@ public final class Prefs { @Retention(RetentionPolicy.SOURCE) @StringDef({ - Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, - Key.DEBUG_MODE_ENABLED, - Key.HOTSPOT_TILE_LAST_USED, - Key.COLOR_INVERSION_TILE_LAST_USED, - Key.DND_TILE_VISIBLE, - Key.DND_TILE_COMBINED_ICON, - Key.DND_CONFIRMED_PRIORITY_INTRODUCTION, - Key.DND_CONFIRMED_SILENCE_INTRODUCTION, - Key.DND_FAVORITE_BUCKET_INDEX, - Key.DND_NONE_SELECTED, - Key.DND_FAVORITE_ZEN, - Key.QS_HOTSPOT_ADDED, - Key.QS_DATA_SAVER_ADDED, - Key.QS_DATA_SAVER_DIALOG_SHOWN, - Key.QS_INVERT_COLORS_ADDED, - Key.QS_WORK_ADDED, - Key.QS_NIGHTDISPLAY_ADDED, - Key.QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT, - Key.SEEN_MULTI_USER, - Key.NUM_APPS_LAUNCHED, - Key.HAS_SEEN_RECENTS_ONBOARDING, + Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, + Key.DEBUG_MODE_ENABLED, + Key.HOTSPOT_TILE_LAST_USED, + Key.COLOR_INVERSION_TILE_LAST_USED, + Key.DND_TILE_VISIBLE, + Key.DND_TILE_COMBINED_ICON, + Key.DND_CONFIRMED_PRIORITY_INTRODUCTION, + Key.DND_CONFIRMED_SILENCE_INTRODUCTION, + Key.DND_FAVORITE_BUCKET_INDEX, + Key.DND_NONE_SELECTED, + Key.DND_FAVORITE_ZEN, + Key.QS_HOTSPOT_ADDED, + Key.QS_DATA_SAVER_ADDED, + Key.QS_DATA_SAVER_DIALOG_SHOWN, + Key.QS_INVERT_COLORS_ADDED, + Key.QS_WORK_ADDED, + Key.QS_NIGHTDISPLAY_ADDED, + Key.QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT, + Key.SEEN_MULTI_USER, + Key.NUM_APPS_LAUNCHED, + Key.HAS_SEEN_RECENTS_ONBOARDING, + Key.SEEN_RINGER_GUIDANCE_COUNT }) public @interface Key { @Deprecated @@ -85,6 +86,7 @@ public final class Prefs { String SEEN_MULTI_USER = "HasSeenMultiUser"; String NUM_APPS_LAUNCHED = "NumAppsLaunched"; String HAS_SEEN_RECENTS_ONBOARDING = "HasSeenRecentsOnboarding"; + String SEEN_RINGER_GUIDANCE_COUNT = "RingerGuidanceCount"; } public static boolean getBoolean(Context context, @Key String key, boolean defaultValue) { diff --git a/packages/SystemUI/src/com/android/systemui/volume/OutputChooserDialog.java b/packages/SystemUI/src/com/android/systemui/volume/OutputChooserDialog.java deleted file mode 100644 index 6ed07f8d2c37..000000000000 --- a/packages/SystemUI/src/com/android/systemui/volume/OutputChooserDialog.java +++ /dev/null @@ -1,534 +0,0 @@ -/* - * Copyright (C) 2017 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.volume; - -import static android.support.v7.media.MediaRouter.RouteInfo.CONNECTION_STATE_CONNECTED; -import static android.support.v7.media.MediaRouter.RouteInfo.CONNECTION_STATE_CONNECTING; -import static android.support.v7.media.MediaRouter.UNSELECT_REASON_DISCONNECTED; - -import static com.android.settingslib.bluetooth.Utils.getBtClassDrawableWithDescription; - -import android.app.Dialog; -import android.bluetooth.BluetoothClass; -import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothProfile; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.IntentFilter; -import android.graphics.Color; -import android.graphics.drawable.ColorDrawable; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.net.wifi.WifiManager; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.os.SystemClock; -import android.support.v7.media.MediaControlIntent; -import android.support.v7.media.MediaRouteSelector; -import android.support.v7.media.MediaRouter; -import android.telecom.TelecomManager; -import android.util.Log; -import android.util.Pair; -import android.view.Window; -import android.view.WindowManager; - -import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.nano.MetricsProto; -import com.android.settingslib.Utils; -import com.android.settingslib.bluetooth.CachedBluetoothDevice; -import com.android.systemui.Dependency; -import com.android.systemui.HardwareUiLayout; -import com.android.systemui.Interpolators; -import com.android.systemui.R; -import com.android.systemui.plugins.VolumeDialogController; -import com.android.systemui.statusbar.policy.BluetoothController; - -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Comparator; -import java.util.List; - -public class OutputChooserDialog extends Dialog - implements DialogInterface.OnDismissListener, OutputChooserLayout.Callback { - - private static final String TAG = Util.logTag(OutputChooserDialog.class); - private static final int MAX_DEVICES = 10; - - private static final long UPDATE_DELAY_MS = 300L; - private static final int MSG_UPDATE_ITEMS = 1; - - private final Context mContext; - private final BluetoothController mBluetoothController; - private WifiManager mWifiManager; - private OutputChooserLayout mView; - private final MediaRouterWrapper mRouter; - private final MediaRouterCallback mRouterCallback; - private long mLastUpdateTime; - static final boolean INCLUDE_MEDIA_ROUTES = false; - private boolean mIsInCall; - protected boolean isAttached; - - private final MediaRouteSelector mRouteSelector; - private Drawable mDefaultIcon; - private Drawable mTvIcon; - private Drawable mSpeakerIcon; - private Drawable mSpeakerGroupIcon; - private HardwareUiLayout mHardwareLayout; - private final VolumeDialogController mController; - - public OutputChooserDialog(Context context, MediaRouterWrapper router) { - super(context, com.android.systemui.R.style.qs_theme); - mContext = context; - mBluetoothController = Dependency.get(BluetoothController.class); - mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); - TelecomManager tm = (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE); - mIsInCall = tm.isInCall(); - mRouter = router; - mRouterCallback = new MediaRouterCallback(); - mRouteSelector = new MediaRouteSelector.Builder() - .addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK) - .build(); - - final IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); - context.registerReceiver(mReceiver, filter); - - mController = Dependency.get(VolumeDialogController.class); - - // Window initialization - Window window = getWindow(); - window.requestFeature(Window.FEATURE_NO_TITLE); - window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); - window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND - | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR); - window.addFlags( - WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN - | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL - | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED - | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH - | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED); - window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY); - } - - protected void setIsInCall(boolean inCall) { - mIsInCall = inCall; - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.output_chooser); - setCanceledOnTouchOutside(true); - setOnDismissListener(this::onDismiss); - - mView = findViewById(R.id.output_chooser); - mHardwareLayout = HardwareUiLayout.get(mView); - mHardwareLayout.setOutsideTouchListener(view -> dismiss()); - mHardwareLayout.setSwapOrientation(false); - mView.setCallback(this); - - if (mIsInCall) { - mView.setTitle(R.string.output_calls_title); - } else { - mView.setTitle(R.string.output_title); - } - - mDefaultIcon = mContext.getDrawable(R.drawable.ic_cast); - mTvIcon = mContext.getDrawable(R.drawable.ic_tv); - mSpeakerIcon = mContext.getDrawable(R.drawable.ic_speaker); - mSpeakerGroupIcon = mContext.getDrawable(R.drawable.ic_speaker_group); - - final boolean wifiOff = !mWifiManager.isWifiEnabled(); - final boolean btOff = !mBluetoothController.isBluetoothEnabled(); - if (wifiOff && btOff) { - mView.setEmptyState(getDisabledServicesMessage(wifiOff, btOff)); - } - // time out after 5 seconds - mView.postDelayed(() -> updateItems(true), 5000); - } - - protected void cleanUp() {} - - - @Override - protected void onStart() { - super.onStart(); - } - - @Override - public void onAttachedToWindow() { - super.onAttachedToWindow(); - - if (!mIsInCall && INCLUDE_MEDIA_ROUTES) { - mRouter.addCallback(mRouteSelector, mRouterCallback, - MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN); - } - mBluetoothController.addCallback(mCallback); - mController.addCallback(mControllerCallbackH, mHandler); - isAttached = true; - } - - @Override - public void onDetachedFromWindow() { - isAttached = false; - mRouter.removeCallback(mRouterCallback); - mController.removeCallback(mControllerCallbackH); - mBluetoothController.removeCallback(mCallback); - super.onDetachedFromWindow(); - } - - @Override - public void onDismiss(DialogInterface unused) { - mContext.unregisterReceiver(mReceiver); - cleanUp(); - } - - @Override - public void show() { - super.show(); - Dependency.get(MetricsLogger.class).visible(MetricsProto.MetricsEvent.OUTPUT_CHOOSER); - mHardwareLayout.setTranslationX(getAnimTranslation()); - mHardwareLayout.setAlpha(0); - mHardwareLayout.animate() - .alpha(1) - .translationX(0) - .setDuration(300) - .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) - .withEndAction(() -> getWindow().getDecorView().requestAccessibilityFocus()) - .start(); - } - - @Override - public void dismiss() { - Dependency.get(MetricsLogger.class).hidden(MetricsProto.MetricsEvent.OUTPUT_CHOOSER); - mHardwareLayout.setTranslationX(0); - mHardwareLayout.setAlpha(1); - mHardwareLayout.animate() - .alpha(0) - .translationX(getAnimTranslation()) - .setDuration(300) - .withEndAction(() -> super.dismiss()) - .setInterpolator(new SystemUIInterpolators.LogAccelerateInterpolator()) - .start(); - } - - private float getAnimTranslation() { - return getContext().getResources().getDimension( - com.android.systemui.R.dimen.output_chooser_panel_width) / 2; - } - - @Override - public void onDetailItemClick(OutputChooserLayout.Item item) { - if (item == null || item.tag == null) return; - if (item.deviceType == OutputChooserLayout.Item.DEVICE_TYPE_BT) { - final CachedBluetoothDevice device = (CachedBluetoothDevice) item.tag; - if (device.getMaxConnectionState() == BluetoothProfile.STATE_DISCONNECTED) { - Dependency.get(MetricsLogger.class).action( - MetricsProto.MetricsEvent.ACTION_OUTPUT_CHOOSER_CONNECT); - mBluetoothController.connect(device); - } - } else if (item.deviceType == OutputChooserLayout.Item.DEVICE_TYPE_MEDIA_ROUTER) { - final MediaRouter.RouteInfo route = (MediaRouter.RouteInfo) item.tag; - if (route.isEnabled()) { - Dependency.get(MetricsLogger.class).action( - MetricsProto.MetricsEvent.ACTION_OUTPUT_CHOOSER_CONNECT); - route.select(); - } - } - } - - @Override - public void onDetailItemDisconnect(OutputChooserLayout.Item item) { - if (item == null || item.tag == null) return; - if (item.deviceType == OutputChooserLayout.Item.DEVICE_TYPE_BT) { - final CachedBluetoothDevice device = (CachedBluetoothDevice) item.tag; - Dependency.get(MetricsLogger.class).action( - MetricsProto.MetricsEvent.ACTION_OUTPUT_CHOOSER_DISCONNECT); - mBluetoothController.disconnect(device); - } else if (item.deviceType == OutputChooserLayout.Item.DEVICE_TYPE_MEDIA_ROUTER) { - Dependency.get(MetricsLogger.class).action( - MetricsProto.MetricsEvent.ACTION_OUTPUT_CHOOSER_DISCONNECT); - mRouter.unselect(UNSELECT_REASON_DISCONNECTED); - } - } - - private void updateItems(boolean timeout) { - if (SystemClock.uptimeMillis() - mLastUpdateTime < UPDATE_DELAY_MS) { - mHandler.removeMessages(MSG_UPDATE_ITEMS); - mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_UPDATE_ITEMS, timeout), - mLastUpdateTime + UPDATE_DELAY_MS); - return; - } - mLastUpdateTime = SystemClock.uptimeMillis(); - if (mView == null) return; - ArrayList<OutputChooserLayout.Item> items = new ArrayList<>(); - - // Add bluetooth devices - addBluetoothDevices(items); - - // Add remote displays - if (!mIsInCall && INCLUDE_MEDIA_ROUTES) { - addRemoteDisplayRoutes(items); - } - - items.sort(ItemComparator.sInstance); - - if (items.size() == 0 && timeout) { - String emptyMessage = mContext.getString(R.string.output_none_found); - final boolean wifiOff = !mWifiManager.isWifiEnabled(); - final boolean btOff = !mBluetoothController.isBluetoothEnabled(); - if (wifiOff || btOff) { - emptyMessage = getDisabledServicesMessage(wifiOff, btOff); - } - mView.setEmptyState(emptyMessage); - } - - mView.setItems(items.toArray(new OutputChooserLayout.Item[items.size()])); - } - - private String getDisabledServicesMessage(boolean wifiOff, boolean btOff) { - return mContext.getString(R.string.output_none_found_service_off, - wifiOff && btOff ? mContext.getString(R.string.output_service_bt_wifi) - : wifiOff ? mContext.getString(R.string.output_service_wifi) - : mContext.getString(R.string.output_service_bt)); - } - - private void addBluetoothDevices(List<OutputChooserLayout.Item> items) { - final Collection<CachedBluetoothDevice> devices = mBluetoothController.getDevices(); - if (devices != null) { - int connectedDevices = 0; - int count = 0; - for (CachedBluetoothDevice device : devices) { - if (mBluetoothController.getBondState(device) == BluetoothDevice.BOND_NONE) continue; - final int majorClass = device.getBtClass().getMajorDeviceClass(); - if (majorClass != BluetoothClass.Device.Major.AUDIO_VIDEO - && majorClass != BluetoothClass.Device.Major.UNCATEGORIZED) { - continue; - } - final OutputChooserLayout.Item item = new OutputChooserLayout.Item(); - item.iconResId = R.drawable.ic_qs_bluetooth_on; - item.line1 = device.getName(); - item.tag = device; - item.deviceType = OutputChooserLayout.Item.DEVICE_TYPE_BT; - int state = device.getMaxConnectionState(); - if (state == BluetoothProfile.STATE_CONNECTED) { - item.iconResId = R.drawable.ic_qs_bluetooth_connected; - int batteryLevel = device.getBatteryLevel(); - if (batteryLevel != BluetoothDevice.BATTERY_LEVEL_UNKNOWN) { - Pair<Drawable, String> pair = - getBtClassDrawableWithDescription(getContext(), device); - item.icon = pair.first; - item.line2 = mContext.getString( - R.string.quick_settings_connected_battery_level, - Utils.formatPercentage(batteryLevel)); - } else { - item.line2 = mContext.getString(R.string.quick_settings_connected); - } - item.canDisconnect = true; - items.add(connectedDevices, item); - connectedDevices++; - } else if (state == BluetoothProfile.STATE_CONNECTING) { - item.iconResId = R.drawable.ic_qs_bluetooth_connecting; - item.line2 = mContext.getString(R.string.quick_settings_connecting); - items.add(connectedDevices, item); - } else { - items.add(item); - } - if (++count == MAX_DEVICES) { - break; - } - } - } - } - - private void addRemoteDisplayRoutes(List<OutputChooserLayout.Item> items) { - List<MediaRouter.RouteInfo> routes = mRouter.getRoutes(); - for(MediaRouter.RouteInfo route : routes) { - if (route.isDefaultOrBluetooth() || !route.isEnabled() - || !route.matchesSelector(mRouteSelector)) { - continue; - } - final OutputChooserLayout.Item item = new OutputChooserLayout.Item(); - item.icon = getIconDrawable(route); - item.line1 = route.getName(); - item.tag = route; - item.deviceType = OutputChooserLayout.Item.DEVICE_TYPE_MEDIA_ROUTER; - if (route.getConnectionState() == CONNECTION_STATE_CONNECTING) { - mContext.getString(R.string.quick_settings_connecting); - } else { - item.line2 = route.getDescription(); - } - - if (route.getConnectionState() == CONNECTION_STATE_CONNECTED) { - item.canDisconnect = true; - } - items.add(item); - } - } - - private Drawable getIconDrawable(MediaRouter.RouteInfo route) { - Uri iconUri = route.getIconUri(); - if (iconUri != null) { - try { - InputStream is = getContext().getContentResolver().openInputStream(iconUri); - Drawable drawable = Drawable.createFromStream(is, null); - if (drawable != null) { - return drawable; - } - } catch (IOException e) { - Log.w(TAG, "Failed to load " + iconUri, e); - // Falls back. - } - } - return getDefaultIconDrawable(route); - } - - private Drawable getDefaultIconDrawable(MediaRouter.RouteInfo route) { - // If the type of the receiver device is specified, use it. - switch (route.getDeviceType()) { - case MediaRouter.RouteInfo.DEVICE_TYPE_TV: - return mTvIcon; - case MediaRouter.RouteInfo.DEVICE_TYPE_SPEAKER: - return mSpeakerIcon; - } - - // Otherwise, make the best guess based on other route information. - if (route instanceof MediaRouter.RouteGroup) { - // Only speakers can be grouped for now. - return mSpeakerGroupIcon; - } - return mDefaultIcon; - } - - private final class MediaRouterCallback extends MediaRouter.Callback { - @Override - public void onRouteAdded(MediaRouter router, MediaRouter.RouteInfo info) { - updateItems(false); - } - - @Override - public void onRouteRemoved(MediaRouter router, MediaRouter.RouteInfo info) { - updateItems(false); - } - - @Override - public void onRouteChanged(MediaRouter router, MediaRouter.RouteInfo info) { - updateItems(false); - } - - @Override - public void onRouteSelected(MediaRouter router, MediaRouter.RouteInfo route) { - updateItems(false); - } - } - - private final BroadcastReceiver mReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) { - if (D.BUG) Log.d(TAG, "Received ACTION_CLOSE_SYSTEM_DIALOGS"); - cancel(); - cleanUp(); - } - } - }; - - private final BluetoothController.Callback mCallback = new BluetoothController.Callback() { - @Override - public void onBluetoothStateChange(boolean enabled) { - updateItems(false); - } - - @Override - public void onBluetoothDevicesChanged() { - updateItems(false); - } - }; - - static final class ItemComparator implements Comparator<OutputChooserLayout.Item> { - public static final ItemComparator sInstance = new ItemComparator(); - - @Override - public int compare(OutputChooserLayout.Item lhs, OutputChooserLayout.Item rhs) { - // Connected item(s) first - if (lhs.canDisconnect != rhs.canDisconnect) { - return Boolean.compare(rhs.canDisconnect, lhs.canDisconnect); - } - // Bluetooth items before media routes - if (lhs.deviceType != rhs.deviceType) { - return Integer.compare(lhs.deviceType, rhs.deviceType); - } - // then by name - return lhs.line1.toString().compareToIgnoreCase(rhs.line1.toString()); - } - } - - private final Handler mHandler = new Handler() { - @Override - public void handleMessage(Message message) { - switch (message.what) { - case MSG_UPDATE_ITEMS: - updateItems((Boolean) message.obj); - break; - } - } - }; - - private final VolumeDialogController.Callbacks mControllerCallbackH - = new VolumeDialogController.Callbacks() { - @Override - public void onShowRequested(int reason) { - dismiss(); - } - - @Override - public void onDismissRequested(int reason) {} - - @Override - public void onScreenOff() { - dismiss(); - } - - @Override - public void onStateChanged(VolumeDialogController.State state) {} - - @Override - public void onLayoutDirectionChanged(int layoutDirection) {} - - @Override - public void onConfigurationChanged() {} - - @Override - public void onShowVibrateHint() {} - - @Override - public void onShowSilentHint() {} - - @Override - public void onShowSafetyWarning(int flags) {} - - @Override - public void onAccessibilityModeChanged(Boolean showA11yStream) {} - - @Override - public void onConnectedDeviceChanged(String deviceName) {} - }; -}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/volume/OutputChooserLayout.java b/packages/SystemUI/src/com/android/systemui/volume/OutputChooserLayout.java deleted file mode 100644 index d4c6f897846e..000000000000 --- a/packages/SystemUI/src/com/android/systemui/volume/OutputChooserLayout.java +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright (C) 2017 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.volume; - -import android.content.Context; -import android.content.res.Configuration; -import android.graphics.drawable.Drawable; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.text.TextUtils; -import android.util.AttributeSet; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.BaseAdapter; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; - -import com.android.systemui.FontSizeUtils; -import com.android.systemui.R; -import com.android.systemui.qs.AutoSizingList; - -/** - * Limited height list of devices. - */ -public class OutputChooserLayout extends LinearLayout { - private static final String TAG = "OutputChooserLayout"; - private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - - private final Context mContext; - private final H mHandler = new H(); - private final Adapter mAdapter = new Adapter(); - - private String mTag; - private Callback mCallback; - private boolean mItemsVisible = true; - private AutoSizingList mItemList; - private View mEmpty; - private TextView mEmptyText; - private TextView mTitle; - - private Item[] mItems; - - public OutputChooserLayout(Context context, AttributeSet attrs) { - super(context, attrs); - mContext = context; - mTag = TAG; - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - mItemList = findViewById(android.R.id.list); - mItemList.setVisibility(GONE); - mItemList.setAdapter(mAdapter); - mEmpty = findViewById(android.R.id.empty); - mEmpty.setVisibility(GONE); - mEmptyText = mEmpty.findViewById(R.id.empty_text); - mTitle = findViewById(R.id.title); - } - - @Override - protected void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - FontSizeUtils.updateFontSize(mEmptyText, R.dimen.qs_detail_empty_text_size); - int count = mItemList.getChildCount(); - for (int i = 0; i < count; i++) { - View item = mItemList.getChildAt(i); - FontSizeUtils.updateFontSize(item, R.id.empty_text, - R.dimen.qs_detail_item_primary_text_size); - FontSizeUtils.updateFontSize(item, android.R.id.summary, - R.dimen.qs_detail_item_secondary_text_size); - FontSizeUtils.updateFontSize(item, android.R.id.title, - R.dimen.qs_detail_header_text_size); - } - } - - public void setTitle(int title) { - mTitle.setText(title); - } - - public void setEmptyState(String text) { - mEmptyText.setText(text); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - if (DEBUG) Log.d(mTag, "onAttachedToWindow"); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - if (DEBUG) Log.d(mTag, "onDetachedFromWindow"); - mCallback = null; - } - - public void setCallback(Callback callback) { - mHandler.removeMessages(H.SET_CALLBACK); - mHandler.obtainMessage(H.SET_CALLBACK, callback).sendToTarget(); - } - - public void setItems(Item[] items) { - mHandler.removeMessages(H.SET_ITEMS); - mHandler.obtainMessage(H.SET_ITEMS, items).sendToTarget(); - } - - public void setItemsVisible(boolean visible) { - mHandler.removeMessages(H.SET_ITEMS_VISIBLE); - mHandler.obtainMessage(H.SET_ITEMS_VISIBLE, visible ? 1 : 0, 0).sendToTarget(); - } - - private void handleSetCallback(Callback callback) { - mCallback = callback; - } - - private void handleSetItems(Item[] items) { - final int itemCount = items != null ? items.length : 0; - mEmpty.setVisibility(itemCount == 0 ? VISIBLE : GONE); - mItemList.setVisibility(itemCount == 0 ? GONE : VISIBLE); - mItems = items; - mAdapter.notifyDataSetChanged(); - } - - private void handleSetItemsVisible(boolean visible) { - if (mItemsVisible == visible) return; - mItemsVisible = visible; - for (int i = 0; i < mItemList.getChildCount(); i++) { - mItemList.getChildAt(i).setVisibility(mItemsVisible ? VISIBLE : INVISIBLE); - } - } - - private class Adapter extends BaseAdapter { - - @Override - public int getCount() { - return mItems != null ? mItems.length : 0; - } - - @Override - public Object getItem(int position) { - return mItems[position]; - } - - @Override - public long getItemId(int position) { - return 0; - } - - @Override - public View getView(int position, View view, ViewGroup parent) { - final Item item = mItems[position]; - if (view == null) { - view = LayoutInflater.from(mContext).inflate(R.layout.output_chooser_item, parent, - false); - } - view.setVisibility(mItemsVisible ? VISIBLE : INVISIBLE); - final ImageView iv = view.findViewById(android.R.id.icon); - if (item.icon != null) { - iv.setImageDrawable(item.icon); - } else { - iv.setImageResource(item.iconResId); - } - final TextView title = view.findViewById(android.R.id.title); - title.setText(item.line1); - final TextView summary = view.findViewById(android.R.id.summary); - final boolean twoLines = !TextUtils.isEmpty(item.line2); - title.setMaxLines(twoLines ? 1 : 2); - summary.setVisibility(twoLines ? VISIBLE : GONE); - summary.setText(twoLines ? item.line2 : null); - view.setOnClickListener(v -> { - if (mCallback != null) { - mCallback.onDetailItemClick(item); - } - }); - - final ImageView icon2 = view.findViewById(android.R.id.icon2); - if (item.canDisconnect) { - icon2.setImageResource(R.drawable.ic_qs_cancel); - icon2.setVisibility(VISIBLE); - icon2.setClickable(true); - icon2.setOnClickListener(v -> { - if (mCallback != null) { - mCallback.onDetailItemDisconnect(item); - } - }); - } else if (item.icon2 != -1) { - icon2.setVisibility(VISIBLE); - icon2.setImageResource(item.icon2); - icon2.setClickable(false); - } else { - icon2.setVisibility(GONE); - } - - return view; - } - }; - - private class H extends Handler { - private static final int SET_ITEMS = 1; - private static final int SET_CALLBACK = 2; - private static final int SET_ITEMS_VISIBLE = 3; - - public H() { - super(Looper.getMainLooper()); - } - - @Override - public void handleMessage(Message msg) { - if (msg.what == SET_ITEMS) { - handleSetItems((Item[]) msg.obj); - } else if (msg.what == SET_CALLBACK) { - handleSetCallback((OutputChooserLayout.Callback) msg.obj); - } else if (msg.what == SET_ITEMS_VISIBLE) { - handleSetItemsVisible(msg.arg1 != 0); - } - } - } - - public static class Item { - public static int DEVICE_TYPE_BT = 1; - public static int DEVICE_TYPE_MEDIA_ROUTER = 2; - public int iconResId; - public Drawable icon; - public Drawable overlay; - public CharSequence line1; - public CharSequence line2; - public Object tag; - public boolean canDisconnect; - public int icon2 = -1; - public int deviceType = 0; - } - - public interface Callback { - void onDetailItemClick(Item item); - void onDetailItemDisconnect(Item item); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java index 3c29b7740102..7c71b2a058f5 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java @@ -110,11 +110,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa private boolean mShowA11yStream; private boolean mShowVolumeDialog; private boolean mShowSafetyWarning; - private DeviceCallback mDeviceCallback = new DeviceCallback(); private final NotificationManager mNotificationManager; - @GuardedBy("mLock") - private List<AudioDeviceInfo> mConnectedDevices = new ArrayList<>(); - private Object mLock = new Object(); private boolean mDestroyed; private VolumePolicy mVolumePolicy; @@ -192,7 +188,6 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa } catch (SecurityException e) { Log.w(TAG, "No access to media sessions", e); } - mAudio.registerAudioDeviceCallback(mDeviceCallback, mWorker); } public void setVolumePolicy(VolumePolicy policy) { @@ -218,7 +213,6 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa mMediaSessions.destroy(); mObserver.destroy(); mReceiver.destroy(); - mAudio.unregisterAudioDeviceCallback(mDeviceCallback); mWorkerThread.quitSafely(); } @@ -842,18 +836,6 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa }); } } - - @Override - public void onConnectedDeviceChanged(String deviceName) { - for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) { - entry.getValue().post(new Runnable() { - @Override - public void run() { - entry.getKey().onConnectedDeviceChanged(deviceName); - } - }); - } - } } @@ -1060,33 +1042,6 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa } } - protected final class DeviceCallback extends AudioDeviceCallback { - public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) { - synchronized (mLock) { - for (AudioDeviceInfo info : addedDevices) { - if (info.isSink() - && (info.getType() == AudioDeviceInfo.TYPE_BLUETOOTH_A2DP - || info.getType() == AudioDeviceInfo.TYPE_BLUETOOTH_SCO)) { - mConnectedDevices.add(info); - mCallbacks.onConnectedDeviceChanged(info.getProductName().toString()); - } - } - } - } - - public void onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices) { - synchronized (mLock) { - for (AudioDeviceInfo info : removedDevices) { - mConnectedDevices.remove(info); - } - - if (mConnectedDevices.size() == 0) { - mCallbacks.onConnectedDeviceChanged(null); - } - } - } - } - public interface UserActivityListener { void onUserActivity(); } diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java index 1e8e98ca2e42..90a9fc877fea 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java @@ -18,22 +18,22 @@ package com.android.systemui.volume; import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK; import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_GENERIC; +import static android.media.AudioManager.RINGER_MODE_MAX; +import static android.media.AudioManager.RINGER_MODE_NORMAL; +import static android.media.AudioManager.RINGER_MODE_SILENT; +import static android.media.AudioManager.RINGER_MODE_VIBRATE; import static android.media.AudioManager.STREAM_ACCESSIBILITY; -import static com.android.systemui.volume.Events.DISMISS_REASON_OUTPUT_CHOOSER; import static com.android.systemui.volume.Events.DISMISS_REASON_SETTINGS_CLICKED; -import static com.android.systemui.volume.Events.DISMISS_REASON_TOUCH_OUTSIDE; import android.accessibilityservice.AccessibilityServiceInfo; import android.animation.ObjectAnimator; -import android.annotation.NonNull; import android.annotation.SuppressLint; import android.app.Dialog; import android.app.KeyguardManager; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; -import android.content.pm.PackageManager; import android.content.res.ColorStateList; import android.content.res.Resources; import android.graphics.Color; @@ -48,9 +48,7 @@ import android.os.Message; import android.os.SystemClock; import android.provider.Settings; import android.provider.Settings.Global; -import android.support.v7.media.MediaRouter; import android.text.InputFilter; -import android.text.TextUtils; import android.util.Log; import android.util.Slog; import android.util.SparseBooleanArray; @@ -60,7 +58,6 @@ import android.view.MotionEvent; import android.view.View; import android.view.View.AccessibilityDelegate; import android.view.View.OnAttachStateChangeListener; -import android.view.View.OnClickListener; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; @@ -72,9 +69,11 @@ import android.widget.ImageView; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.TextView; +import android.widget.Toast; import com.android.settingslib.Utils; import com.android.systemui.Dependency; +import com.android.systemui.Prefs; import com.android.systemui.R; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.VolumeDialog; @@ -108,18 +107,16 @@ public class VolumeDialogImpl implements VolumeDialog { private CustomDialog mDialog; private ViewGroup mDialogView; private ViewGroup mDialogRowsView; - private ViewGroup mFooter; + private ViewGroup mRinger; private ImageButton mRingerIcon; + private ImageButton mSettingsIcon; private ImageView mZenIcon; - private TextView mRingerStatus; - private TextView mRingerTitle; private final List<VolumeRow> mRows = new ArrayList<>(); private ConfigurableTexts mConfigurableTexts; private final SparseBooleanArray mDynamic = new SparseBooleanArray(); private final KeyguardManager mKeyguard; private final AccessibilityManagerWrapper mAccessibilityMgr; private final Object mSafetyWarningLock = new Object(); - private final Object mOutputChooserLock = new Object(); private final Accessibility mAccessibility = new Accessibility(); private final ColorStateList mActiveSliderTint; private final ColorStateList mInactiveSliderTint; @@ -133,7 +130,6 @@ public class VolumeDialogImpl implements VolumeDialog { private boolean mSilentMode = VolumePrefs.DEFAULT_ENABLE_SILENT_MODE; private State mState; private SafetyWarningDialog mSafetyWarning; - private OutputChooserDialog mOutputChooserDialog; private boolean mHovering = false; public VolumeDialogImpl(Context context) { @@ -215,11 +211,10 @@ public class VolumeDialogImpl implements VolumeDialog { uiLayout.updateRotation(); mDialogRowsView = mDialog.findViewById(R.id.volume_dialog_rows); - mFooter = mDialog.findViewById(R.id.footer); - mRingerIcon = mFooter.findViewById(R.id.ringer_icon); - mRingerStatus = mFooter.findViewById(R.id.ringer_status); - mRingerTitle = mFooter.findViewById(R.id.ringer_title); - mZenIcon = mFooter.findViewById(R.id.dnd_icon); + mRinger = mDialog.findViewById(R.id.ringer); + mRingerIcon = mRinger.findViewById(R.id.ringer_icon); + mZenIcon = mRinger.findViewById(R.id.dnd_icon); + mSettingsIcon = mDialog.findViewById(R.id.settings); if (mRows.isEmpty()) { addRow(AudioManager.STREAM_MUSIC, @@ -244,6 +239,7 @@ public class VolumeDialogImpl implements VolumeDialog { updateRowsH(getActiveRow()); initRingerH(); + initSettingsH(); } protected ViewGroup getDialogView() { @@ -358,10 +354,6 @@ public class VolumeDialogImpl implements VolumeDialog { row.slider.setOnSeekBarChangeListener(new VolumeSeekBarChangeListener(row)); row.anim = null; - row.outputChooser = row.view.findViewById(R.id.output_chooser); - row.outputChooser.setOnClickListener(mClickOutputChooser); - row.connectedDevice = row.view.findViewById(R.id.volume_row_connected_device); - row.icon = row.view.findViewById(R.id.volume_row_icon); row.icon.setImageResource(iconRes); if (row.stream != AudioSystem.STREAM_ACCESSIBILITY) { @@ -396,6 +388,15 @@ public class VolumeDialogImpl implements VolumeDialog { } } + public void initSettingsH() { + mSettingsIcon.setOnClickListener(v -> { + Intent intent = new Intent(Settings.ACTION_SOUND_SETTINGS); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + dismissH(DISMISS_REASON_SETTINGS_CLICKED); + Dependency.get(ActivityStarter.class).startActivity(intent, true /* dismissShade */); + }); + } + public void initRingerH() { mRingerIcon.setOnClickListener(v -> { Events.writeEvent(mContext, Events.EVENT_ICON_CLICK, AudioManager.STREAM_RING, @@ -406,34 +407,55 @@ public class VolumeDialogImpl implements VolumeDialog { } // normal -> vibrate -> silent -> normal (skip vibrate if device doesn't have // a vibrator. + int newRingerMode; final boolean hasVibrator = mController.hasVibrator(); if (mState.ringerModeInternal == AudioManager.RINGER_MODE_NORMAL) { if (hasVibrator) { mController.vibrate(); - mController.setRingerMode(AudioManager.RINGER_MODE_VIBRATE, false); + newRingerMode = AudioManager.RINGER_MODE_VIBRATE; } else { - mController.setRingerMode(AudioManager.RINGER_MODE_SILENT, false); + newRingerMode = AudioManager.RINGER_MODE_SILENT; } } else if (mState.ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE) { - mController.setRingerMode(AudioManager.RINGER_MODE_SILENT, false); + newRingerMode = AudioManager.RINGER_MODE_SILENT; } else { - mController.setRingerMode(AudioManager.RINGER_MODE_NORMAL, false); + newRingerMode = AudioManager.RINGER_MODE_NORMAL; if (ss.level == 0) { mController.setStreamVolume(AudioManager.STREAM_RING, 1); } } updateRingerH(); - }); - mRingerIcon.setOnLongClickListener(v -> { - Intent intent = new Intent(Settings.ACTION_SOUND_SETTINGS); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - dismissH(DISMISS_REASON_SETTINGS_CLICKED); - Dependency.get(ActivityStarter.class).startActivity(intent, true /* dismissShade */); - return true; + + mController.setRingerMode(newRingerMode, false); + maybeShowToastH(newRingerMode); }); updateRingerH(); } + private void maybeShowToastH(int newRingerMode) { + int seenToastCount = Prefs.getInt(mContext, Prefs.Key.SEEN_RINGER_GUIDANCE_COUNT, 0); + + if (seenToastCount > VolumePrefs.SHOW_RINGER_TOAST_COUNT) { + return; + } + int toastText; + switch (newRingerMode) { + case RINGER_MODE_NORMAL: + toastText = R.string.volume_dialog_ringer_guidance_ring; + break; + case RINGER_MODE_SILENT: + toastText = R.string.volume_dialog_ringer_guidance_silent; + break; + case RINGER_MODE_VIBRATE: + default: + toastText = R.string.volume_dialog_ringer_guidance_vibrate; + } + + Toast.makeText(mContext, toastText, Toast.LENGTH_SHORT).show(); + seenToastCount++; + Prefs.putInt(mContext, Prefs.Key.SEEN_RINGER_GUIDANCE_COUNT, seenToastCount); + } + public void show(int reason) { mHandler.obtainMessage(H.SHOW, reason, 0).sendToTarget(); } @@ -501,15 +523,6 @@ public class VolumeDialogImpl implements VolumeDialog { } } - private boolean isAttached() { - return mDialogView != null && mDialogView.isAttachedToWindow(); - } - - private boolean hasTouchFeature() { - final PackageManager pm = mContext.getPackageManager(); - return pm.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN); - } - private boolean shouldBeVisibleH(VolumeRow row, VolumeRow activeRow) { boolean isActive = row == activeRow; if (row.stream == AudioSystem.STREAM_ACCESSIBILITY) { @@ -536,20 +549,12 @@ public class VolumeDialogImpl implements VolumeDialog { final boolean isActive = row == activeRow; final boolean shouldBeVisible = shouldBeVisibleH(row, activeRow); Util.setVisOrGone(row.view, shouldBeVisible); - Util.setVisOrGone(row.header, shouldBeVisible); if (row.view.isShown()) { updateVolumeRowSliderTintH(row, isActive); } } } - protected void updateConnectedDeviceH(String deviceName) { - for (final VolumeRow row : mRows) { - row.connectedDevice.setText(deviceName); - Util.setVisOrGone(row.connectedDevice, !TextUtils.isEmpty(deviceName)); - } - } - protected void updateRingerH() { if (mState != null) { final StreamState ss = mState.states.get(AudioManager.STREAM_RING); @@ -560,12 +565,10 @@ public class VolumeDialogImpl implements VolumeDialog { enableRingerViewsH(mState.zenMode == Global.ZEN_MODE_OFF || !mState.disallowRinger); switch (mState.ringerModeInternal) { case AudioManager.RINGER_MODE_VIBRATE: - mRingerStatus.setText(R.string.volume_ringer_status_vibrate); mRingerIcon.setImageResource(R.drawable.ic_volume_ringer_vibrate); mRingerIcon.setTag(Events.ICON_STATE_VIBRATE); break; case AudioManager.RINGER_MODE_SILENT: - mRingerStatus.setText(R.string.volume_ringer_status_silent); mRingerIcon.setImageResource(R.drawable.ic_volume_ringer_mute); mRingerIcon.setContentDescription(mContext.getString( R.string.volume_stream_content_description_unmute, @@ -576,14 +579,12 @@ public class VolumeDialogImpl implements VolumeDialog { default: boolean muted = (mAutomute && ss.level == 0) || ss.muted; if (muted) { - mRingerStatus.setText(R.string.volume_ringer_status_silent); mRingerIcon.setImageResource(R.drawable.ic_volume_ringer_mute); mRingerIcon.setContentDescription(mContext.getString( R.string.volume_stream_content_description_unmute, getStreamLabelH(ss))); mRingerIcon.setTag(Events.ICON_STATE_MUTE); } else { - mRingerStatus.setText(R.string.volume_ringer_status_normal); mRingerIcon.setImageResource(R.drawable.ic_volume_ringer); if (mController.hasVibrator()) { mRingerIcon.setContentDescription(mContext.getString( @@ -603,12 +604,11 @@ public class VolumeDialogImpl implements VolumeDialog { } /** - * Toggles enable state of views in a VolumeRow (not including seekbar, outputChooser or icon) + * Toggles enable state of views in a VolumeRow (not including seekbar or icon) * Hides/shows zen icon * @param enable whether to enable volume row views and hide dnd icon */ private void enableVolumeRowViewsH(VolumeRow row, boolean enable) { - row.header.setEnabled(enable); row.dndIcon.setVisibility(enable ? View.GONE : View.VISIBLE); } @@ -618,8 +618,6 @@ public class VolumeDialogImpl implements VolumeDialog { * @param enable whether to enable ringer views and hide dnd icon */ private void enableRingerViewsH(boolean enable) { - mRingerTitle.setEnabled(enable); - mRingerStatus.setEnabled(enable); mRingerIcon.setEnabled(enable); mZenIcon.setVisibility(enable ? View.GONE : View.VISIBLE); } @@ -889,24 +887,6 @@ public class VolumeDialogImpl implements VolumeDialog { rescheduleTimeoutH(); } - private void showOutputChooserH() { - synchronized (mOutputChooserLock) { - if (mOutputChooserDialog != null) { - return; - } - mOutputChooserDialog = new OutputChooserDialog(mContext, - new MediaRouterWrapper(MediaRouter.getInstance(mContext))) { - @Override - protected void cleanUp() { - synchronized (mOutputChooserLock) { - mOutputChooserDialog = null; - } - } - }; - mOutputChooserDialog.show(); - } - } - private String getStreamLabelH(StreamState ss) { if (ss.remoteLabel != null) { return ss.remoteLabel; @@ -919,14 +899,6 @@ public class VolumeDialogImpl implements VolumeDialog { } } - private final OnClickListener mClickOutputChooser = new OnClickListener() { - @Override - public void onClick(View v) { - dismissH(DISMISS_REASON_OUTPUT_CHOOSER); - showOutputChooserH(); - } - }; - private final VolumeDialogController.Callbacks mControllerCallbackH = new VolumeDialogController.Callbacks() { @Override @@ -991,11 +963,6 @@ public class VolumeDialogImpl implements VolumeDialog { } } - - @Override - public void onConnectedDeviceChanged(String deviceName) { - updateConnectedDeviceH(deviceName); - } }; private final class H extends Handler { @@ -1184,8 +1151,6 @@ public class VolumeDialogImpl implements VolumeDialog { private ObjectAnimator anim; // slider progress animation for non-touch-related updates private int animTargetProgress; private int lastAudibleLevel = 1; - private View outputChooser; - private TextView connectedDevice; private ImageView dndIcon; } } diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java index 04339eb8e802..173400f5e31a 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java @@ -43,6 +43,8 @@ public class VolumePrefs { public static final String PREF_ADJUST_ALARMS = "pref_adjust_alarms"; public static final String PREF_ADJUST_NOTIFICATION = "pref_adjust_notification"; + public static final int SHOW_RINGER_TOAST_COUNT = 9; + public static final boolean DEFAULT_SHOW_HEADERS = true; public static final boolean DEFAULT_ENABLE_AUTOMUTE = true; public static final boolean DEFAULT_ENABLE_SILENT_MODE = true; diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/OutputChooserDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/OutputChooserDialogTest.java deleted file mode 100644 index 922bde787a8d..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/volume/OutputChooserDialogTest.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * 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.systemui.volume; - -import static com.android.systemui.volume.OutputChooserDialog.INCLUDE_MEDIA_ROUTES; - -import static junit.framework.Assert.assertTrue; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.bluetooth.BluetoothProfile; -import android.net.wifi.WifiManager; -import android.support.test.filters.SmallTest; -import android.support.test.runner.AndroidJUnit4; -import android.support.v7.media.MediaRouter; -import android.telecom.TelecomManager; -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; -import android.widget.TextView; - -import com.android.settingslib.bluetooth.CachedBluetoothDevice; -import com.android.systemui.R; -import com.android.systemui.SysuiTestCase; -import com.android.systemui.plugins.VolumeDialogController; -import com.android.systemui.statusbar.policy.BluetoothController; - -import org.junit.After; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -@Ignore -@SmallTest -@RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper -public class OutputChooserDialogTest extends SysuiTestCase { - - OutputChooserDialog mDialog; - - @Mock - private VolumeDialogController mVolumeController; - @Mock - private BluetoothController mController; - @Mock - private WifiManager mWifiManager; - @Mock - private TelecomManager mTelecomManager; - - @Mock - private MediaRouterWrapper mRouter; - - - @Before - public void setup() throws Exception { - MockitoAnnotations.initMocks(this); - - mVolumeController = mDependency.injectMockDependency(VolumeDialogController.class); - mController = mDependency.injectMockDependency(BluetoothController.class); - when(mWifiManager.isWifiEnabled()).thenReturn(true); - - getContext().addMockSystemService(WifiManager.class, mWifiManager); - getContext().addMockSystemService(TelecomManager.class, mTelecomManager); - - mDialog = new OutputChooserDialog(getContext(), mRouter); - } - - @After - public void tearDown() throws Exception { - TestableLooper.get(this).processAllMessages(); - } -/* - @Test - public void testClickMediaRouterItemConnectsMedia() { - mDialog.show(); - - OutputChooserLayout.Item item = new OutputChooserLayout.Item(); - item.deviceType = OutputChooserLayout.Item.DEVICE_TYPE_MEDIA_ROUTER; - MediaRouter.RouteInfo info = mock(MediaRouter.RouteInfo.class); - when(info.isEnabled()).thenReturn(true); - item.tag = info; - - mDialog.onDetailItemClick(item); - verify(info, times(1)).select(); - verify(mController, never()).connect(any()); - mDialog.dismiss(); - } - - @Test - public void testClickBtItemConnectsBt() { - mDialog.show(); - - OutputChooserLayout.Item item = new OutputChooserLayout.Item(); - item.deviceType = OutputChooserLayout.Item.DEVICE_TYPE_BT; - CachedBluetoothDevice btDevice = mock(CachedBluetoothDevice.class); - when(btDevice.getMaxConnectionState()).thenReturn(BluetoothProfile.STATE_DISCONNECTED); - item.tag = btDevice; - - mDialog.onDetailItemClick(item); - verify(mController, times(1)).connect(any()); - mDialog.dismiss(); - } - - @Test - public void testTitleNotInCall() { - mDialog.show(); - - assertTrue(((TextView) mDialog.findViewById(R.id.title)) - .getText().toString().contains("Media")); - mDialog.dismiss(); - } - - @Test - public void testTitleInCall() { - mDialog.setIsInCall(true); - mDialog.show(); - - assertTrue(((TextView) mDialog.findViewById(R.id.title)) - .getText().toString().contains("Phone")); - mDialog.dismiss(); - } -*/ - @Test - public void testNoMediaScanIfInCall() { - mDialog.setIsInCall(true); - mDialog.onAttachedToWindow(); - - verify(mRouter, never()).addCallback(any(), any(), anyInt()); - } - - @Test - public void testRegisterCallbacks() { - mDialog.setIsInCall(false); - mDialog.onAttachedToWindow(); - - if (INCLUDE_MEDIA_ROUTES) { - verify(mRouter, times(1)).addCallback(any(), any(), anyInt()); - } - verify(mController, times(1)).addCallback(any()); - verify(mVolumeController, times(1)).addCallback(any(), any()); - } - - @Test - public void testUnregisterCallbacks() { - mDialog.setIsInCall(false); - mDialog.onDetachedFromWindow(); - - verify(mRouter, times(1)).removeCallback(any()); - verify(mController, times(1)).removeCallback(any()); - verify(mVolumeController, times(1)).removeCallback(any()); - } -} |